Redux: contoh - bagaimana menerapkan namespacing tipe tindakan?

Dibuat pada 23 Sep 2015  ·  32Komentar  ·  Sumber: reduxjs/redux

Saya telah menghabiskan sekitar satu minggu sekarang mencoba menemukan implementasi yang baik dari namespacing jenis tindakan dan telah meluncurkan milik saya sendiri yang didasarkan pada kelas Transisi yang memegang definisi pembuat tindakan, peredam dan daftar transisi turunannya, tetapi pendekatan ini membutuhkan cara terlalu banyak kode pelat ketel dan akan menjadi masalah jika Anda memiliki banyak tindakan yang sangat sederhana.

Dalam semua contoh yang dapat Anda temukan di repo ini dan banyak lainnya masalah ini selalu diabaikan karena beberapa alasan tetapi ini adalah masalah pertama yang saya lihat ketika mulai melihat ke Redux.

Apakah saya melewatkan sesuatu di sini? Kalian tidak memiliki tabrakan penamaan jenis tindakan?

Dapatkah seseorang memperbarui contoh dan menunjukkan kepada saya bagaimana Anda menangani masalah ini atau mengarahkan saya ke arah yang benar?

Kasus khusus saya terkait dengan memiliki 2 panel admin terpisah di frontend. Satu untuk penguji dan satu untuk pelanggan yang statusnya akan disimpan di bagian terpisah dari toko ("testerAccount", "customerAccount"), tetapi keduanya akan dapat melakukan hal yang serupa untuk misalnya ADD_VIDEO_UPLOAD, ADD_COMMENT, dll., Dll., Dll.

Saya akan sangat menghargai bantuan Anda di sini :)

question

Komentar yang paling membantu

String pada dasarnya tidak buruk untuk namespacing. URL adalah string, dan sepertinya berfungsi dengan baik.

Semua 32 komentar

Masukkan accountType ke dalam tindakan? Lihat juga examples/real-world/reducers untuk mengetahui bagaimana Anda dapat menulis pabrik peredam dan menggunakan kode yang sama berkali-kali menghasilkan pereduksi yang merespons tindakan berbeda.

Demikian pula, jangan lupa pembuat tindakan hanyalah fungsi, dan Anda dapat membuat fungsi yang mengembalikan banyak fungsi lainnya.

Saya pikir akan sangat membantu jika Anda memberikan contoh kecil spesifik dari masalah yang Anda katakan diabaikan dalam contoh yang ada.

Kami kemudian dapat membantu Anda menemukan cara untuk menyederhanakan contoh spesifik tersebut. Sangat sulit untuk menyarankan sesuatu yang spesifik dalam menanggapi pertanyaan tanpa kode.

@gaearon Saya tahu ke mana Anda menuju dengan ini, tetapi saya tidak mencoba membuat reduksi yang dapat digunakan kembali, pembuat tindakan atau hal-hal KERING, justru sebaliknya.

Saya mencoba mengisolasi kelompok tindakan satu sama lain sehingga saya dapat memiliki 2 orang yang bekerja pada dua bagian berbeda dari sistem dan memastikan bahwa mereka tidak akan mulai memicu reduksi satu sama lain secara tidak sengaja karena kurangnya namespacing dalam nama jenis tindakan.

Semoga ini membuatnya lebih jelas.

Saya telah memecahkan masalah ini dalam proyek saya dengan menggunakan https://www.npmjs.com/package/flux-constant dalam kombinasi dengan fungsi pembantu super sederhana yang disebut createActionTypes .

Intinya, kode saya akhirnya menjadi:

// create-action-types.js
var fluxConstant = require('flux-constant');
module.exports = function (types) {
    return fluxConstant.set(types);
};

// in foo-action-types.js
module.exports = createAtionTypes([
    'ADD_FOO',
    'REMOVE_FOO'
]);

// in some-store.js
var fooActionTypes = require('foo-action-types');
function (state, action) {
    switch(action.type) {
        case fooActionTypes.ADD_FOO: 

        case fooActionTypes.REMOVE_FOO:
   }
}

Mengapa tidak menyimpan semua jenis tindakan sebagai konstanta di satu tempat?
Kemudian mereka yakin tidak bisa bentrok karena Anda tidak bisa mengekspor nama yang sama dua kali.

Untuk memvisualisasikan ini dengan lebih baik, katakanlah ini adalah status awal toko:


let initialState = {
  "testerAccount": {
    "videoUploads": [],
    "messages": []
  },
  "customerAccount": {
    "videoUploads": [],
    "messages": []
  },
  "systemUserAccount": {
    "videoUploads": [],
    "messages": []
  }
};

Bagaimana Anda akan menghindari benturan nama jenis tindakan saat menerapkan reduksi terpisah untuk menambahkan video atau pesan untuk setiap bagian ini?

@ Gaearon apa yang Anda sarankan tidak menyelesaikan inti masalah, ini lebih merupakan pendekatan lakban karena seiring waktu Anda akan berakhir dengan file tipe besar yang akan menyebabkan banyak masalah.

Ini akan langsung menyebabkan masalah selama penggabungan kode yang nantinya perlu diselesaikan dengan peretasan penamaan, misalnya:

ADD_VIDEO_UPLOAD, ADD_TESTER_VIDEO_UPLOAD, ADD_VIDEO_UPLOAD_IN_SOME_SECTION, dll.

yang merupakan sakit kepala besar lagi.

@koulmomo Inilah yang saya cari, terima kasih :): +1: Sederhana dan kuat.

@ Gaearon Saya pikir kita harus memiliki setidaknya satu contoh yang menggunakan paket ini atau paket baru yang dapat diberi nama redux-constant?

Menurut pendapat saya, mempromosikan pendekatan dalam dokumen / contoh, yang memecahkan masalah namespacing harus menjadi default baru.

Terima kasih atas bantuan Anda dengan ini :)

Dalam contoh Anda, saya tidak begitu mengerti mengapa tidak memiliki satu set jenis, satu generator peredam, dan satu set pembuat tindakan. Tindakan akan berisi properti accountType untuk membedakannya. Pembuat tindakan akan menerimanya sebagai parameter. Pabrik peredam akan menerima accountType dan mengembalikan peredam yang hanya menangani tindakan dengan jenis akun ini.

Saya tidak berpikir flux-constant adalah solusi yang bagus di sini. Tampaknya mengandalkan cek instanceof . Yang berarti Anda tidak dapat membuat serial tindakan Anda dan kemudian memutarnya kembali karena — bam! —Jenis deserialisasi mereka tidak akan cocok dengan yang dihasilkan.

Orang sering mencoba membuat Flux "lebih sederhana" tanpa menyadari bahwa mereka merusak fitur-fitur utamanya .

Dalam contoh Anda, saya tidak begitu mengerti mengapa tidak memiliki satu set jenis, satu generator peredam, dan satu set pembuat tindakan. Tindakan tersebut akan berisi properti accountType untuk membedakannya. Pembuat tindakan akan menerimanya sebagai parameter. Pabrik peredam akan menerima accountType dan mengembalikan peredam yang hanya menangani tindakan dengan jenis akun ini.

Saya disesatkan oleh kesimetrian yang tampak dalam contoh Anda. Saya mengerti sekarang yang Anda maksudkan tidak ada KERING di sini, dan simetri dalam fitur hanya terlihat seperti yang Anda katakan di https://github.com/rackt/redux/issues/786#issuecomment -142649749.

Saya rasa tidak perlu ada perpustakaan di sini. Buat konvensi! Misalnya, jika subproyek atau fitur Anda sangat terpisah, buatlah aturan untuk memanggil jenis tindakan feature/ACTION_TYPE , misalnya testers/UPLOAD_VIDEO atau customers/UPLOAD_VIDEO . Ini sangat bagus jika "grup" ini benar-benar sesuai dengan folder nyata (atau lebih baik — paket) pada disk.

Pelanggaran akan mudah ditemukan dalam tinjauan kode. Jika Anda benar-benar ingin, Anda dapat mengotomatiskan ini tetapi saya tidak dapat melihat apa yang dibawanya pada namespacing manual. Di dalam setiap modul, Anda masih ingin mendeklarasikan semua konstanta dalam satu file untuk memudahkan kontrol atas fitur, mencegah duplikasi upaya yang tidak disengaja, dan sebagai dokumentasi.

Saya semua untuk menambahkan contoh huge-apps dengan pemisahan kode, jenis tindakan namespaced, dll. Itu akan menjadi masalah terpisah.

String pada dasarnya tidak buruk untuk namespacing. URL adalah string, dan sepertinya berfungsi dengan baik.

@gaearon Anda benar, saya lupa tentang masalah serialisasi dengan solusi berdasarkan fluks-konstan.

Saya tidak punya masalah dengan namespacing berbasis string selama kita dapat dengan mudah membedakan modul / ruang nama dengan namanya sendiri.

Solusi berbasis konvensi penamaan adalah sesuatu yang pernah saya lihat sebelumnya:

https://github.com/erikras/ducks-modular-redux

tetapi saya berharap mungkin ada cara yang lebih baik atau "benar" untuk melakukan ini yang didasarkan pada pengalaman Anda.

Saya rasa saya akan mencoba untuk mengubah pendekatan fluks-konstan menjadi sesuatu yang Anda benar-benar dapat membuat serial dalam beberapa cara.

Harap tambahkan contoh "aplikasi-besar" jika Anda menemukan waktu untuk ini karena ini akan menghemat banyak waktu orang lain dan mungkin itu akan mengarah pada pembentukan semacam konvensi yang dapat dengan mudah kita ikuti nanti.

Terima kasih lagi :)

Ya, maaf, sayangnya saya belum mengerjakan aplikasi besar selama beberapa waktu, dan bahkan ketika saya melakukannya, saya sebenarnya suka bahwa kami memiliki satu file raksasa dengan konstanta yang dikelompokkan menjadi beberapa bagian karena memberikan gambaran yang baik tentang apa yang mungkin terjadi di dalam aplikasi.

Saya akan melihat untuk melihat "masalah" ini dijelaskan lebih detail di dokumen. Saya memiliki / memiliki pertanyaan yang sama seperti @pbc. Saya tidak berpikir "Mengapa tidak menyimpan semua jenis tindakan sebagai konstanta di satu tempat?" berfungsi jika Anda menggunakan kembali beberapa modul di seluruh project dan rekomendasi "Buat konvensi!" terdengar sangat mirip seperti BEM di lahan CSS. Namun kami beralih dari modul BEM ke CSS dan saya rasa sesuatu yang mirip dengan modul CSS yang memerlukan nama kelas hash untuk jenis tindakan dalam proyek besar juga.

Sejauh yang saya tahu, tidak ada cara untuk mencapai serialisasi dan tidak adanya konflik.

Konvensi yang baik untuk modul yang dapat digunakan kembali mungkin menggunakan "penyedia keunikan" yang sudah ada, seperti nama domain terbalik, atau nama pengguna / repo di github, atau nama modul terdaftar di npm.


EDIT: Modul CSS melakukan ini dengan menentukan bahasa khusus di atas CSS dan mengawali nama kelas selama prapemrosesan (intinya pada konvensi, tetapi yang dihasilkan).

1 untuk pertanyaan dan diskusi. Saya juga berjuang keras dengan masalah yang sama seperti @pbc . Kebingungan bagi saya adalah bahwa kami telah menggabungkan Reducer untuk reduksi, yang membuat pohon status yang bagus, tetapi tindakan di sisi lain terasa lebih atau kurang seperti global. Dilihat dari tampilannya, semua jenis namespacing harus dilakukan secara manual.

Saya rasa saya telah menemukan solusi untuk jenis tindakan string serializable. Saya pikir itu adalah salah satu situasi di mana pikiran kita memaksakan batasan buatan pada sesuatu.

Ide dasarnya adalah bahwa konstanta tipe tidak perlu dikaitkan dengan cara apa pun ke nilai string. Jadi Anda dapat menggunakan nilai yang dibuat secara acak, jalur file berciri, atau apa pun yang unik untuk nilai string tipe konstan. Di peredam Anda, Anda mengimpor konstanta tipe menurut nama, dan membandingkannya dengan nama. Nama itu mungkin digunakan oleh tindakan lain dan pereduksi lain, tetapi tidak masalah, karena nilainya tidak akan sama.

Contoh di sini: https://gist.github.com/samsch/63a54e868d7fa2b6023a

Ini masuk akal. Anda masih ingin mempertahankan beberapa bagian yang dapat dibaca manusia di nama tindakan, tetapi menghasilkan awalan unik benar-benar berfungsi.

Jika Anda bisa membuktikan bahwa mereka unik, tentunya.
Cara terbaik adalah tetap menggunakan penyedia keunikan yang sudah ada: nama domain terbalik atau nama modul npm.

Namespacing dengan konvensi memiliki risiko tersendiri saat Anda menulis modul daripada yang dapat digunakan di berbagai tempat di luar kendali Anda.

Katakanlah Anda memiliki modul "Geometri", dengan Jenis Tindakan "Area". Modul ini digunakan di dua tempat:

  1. AppA-> Gambar-> Geometri (namespace = "Menggambar / Geometri / Area")
  2. AppB-> Trigonometri-> Bentuk-> Geometri (namespace = "Trigonometri / Bentuk / Area")

Sekarang Anda memiliki dua namespace yang bentrok, tergantung di mana modul Anda digunakan.

  • Bukan ide yang baik untuk membuat kode keras jalur lengkap ini dalam modul Geometri Anda untuk "Area" Jenis Tindakan.
  • Sebaliknya, pertahankan agar nama tetap sederhana: "Area".
  • Dengan cara yang mirip dengan komposisi peredam, susun namespace dengan masing-masing berisi induk untuk menambahkan awalan.

Saya bereksperimen dengan pola berikut:

buat dir untuk setiap jenis koleksi yang berisi:

  • Consts
  • peredam
  • komponen
  • saga

buat const dalam format berikut:

// song-store/song-store-consts.js
export const ADD = 'SONG_STORE.ADD'
export const REMOVE = 'SONG_STORE.REMOVE'

Saat menggunakan konstanta di pereduksi, saga, atau tindakan import semuanya dengan * :

// song-store/song-store-actions.js
import * as SONG_STORE from './song-store-consts'

export function addSongStore(name) {
  return {
    type: SONG_STORE.ADD,
    name
  }
}

export function removeSongStore(songStoreId) {
  return {
    type: SONG_STORE.REMOVE,
    songStoreId
  }
}

Sayangnya tidak bagus untuk gemetar pohon. Alangkah baiknya jika ES6 diizinkan:

import { ADD, REMOVE } as SONG_STORE from './song-store-actions'

Adakah yang tahu jika Webpack 2 dapat secara cerdas mengguncang pohon import * sehingga tidak memaketkan kode untuk ekspor yang tidak digunakan meskipun diimpor dengan * ?

Ini tampaknya menjadi masalah yang sangat umum dan sering muncul di sekitar kantor kami, baik:

  • Konflik nama menyebabkan perilaku yang tidak diinginkan.
  • Mengeluh tentang boilerplate yang terkait dengan pembuatan jenis tindakan unik.

Kami mencoba beberapa solusi berbeda tetapi sepertinya tidak ada yang berhasil:

  1. Menjaga semua jenis tindakan sebagai konstanta di satu tempat tentu saja membuatnya lebih mudah untuk dikelola, tetapi menurut saya ini menjadi sedikit sulit saat aplikasi berkembang.
  2. Nilai yang dihasilkan secara acak yang disebutkan oleh @samsch benar-benar menarik perhatian saya dan itu pasti berhasil, tetapi ya, kehilangan bagian yang dapat dibaca manusia membuatnya lebih sulit untuk dijalani.
  3. Komentar di atas oleh @philholden benar-benar menarik bagi saya, karena kami biasanya menggunakan arsitektur berbasis fitur dan struktur direktorinya cukup deskriptif.

Setelah bereksperimen selama beberapa bulan terakhir, kami memutuskan untuk menggunakan struktur direktori untuk memberi nama jenis tindakan kami. Mengetik ini secara manual menjadi sangat cepat, jadi saya mencoba melakukan sesuatu dengan __filename tetapi ini tidak berhasil karena kode bundling dll. Kemudian saya membuat plugin Babel pertama saya yang mengubah kata kunci __filenamespace menjadi string statis, yang tampaknya berfungsi dengan baik.

Contoh

Di App/testerAccount/index.js :

// Something like this
const ADD_VIDEO_UPLOAD = `${__filenamespace}/ADD_VIDEO_UPLOAD`;
const ADD_COMMENT = `${__filenamespace}/ADD_COMMENT`;

// Will be transformed into something like this
const ADD_VIDEO_UPLOAD = 'App/testerAccount/ADD_VIDEO_UPLOAD';
const ADD_COMMENT = 'App/testerAccount/ADD_COMMENT';

Silahkan mencobanya, semoga bermanfaat. Akan sangat luar biasa untuk mendapatkan umpan balik, terutama dari @pbc atau @gaearon sebagai pembuat terbitan dan pembuat perpustakaan.

https://www.npmjs.com/package/babel-plugin-filenamespace

Saya benar-benar berharap seseorang akan menawarkan "standar". Kami tidak membutuhkan simbol atau objek untuk ini, kami hanya membutuhkan konvensi.

Apakah kita akan melakukan "featureName$actionType" atau "fileName/ACTION_TYPE" atau "PROJECT.FEATURE.ACTION" ? Jika kita semua bisa menyetujui sesuatu, akan lebih mudah untuk membagikan reduksi.

Saya pikir dengan kelangkaan konvensi lain yang tersedia, Bebek telah menjadi standar defacto.

const ACTION = 'app/feature/ACTION'; sudah cukup.

@gaearon selalu menyebutkan bahwa hubungan 1: 1 antara tindakan dan pereduksi mungkin ide yang buruk dan saya sangat setuju. Tapi bagaimana dengan kasus di mana dua pandangan berbeda sebenarnya ingin memanggil peredam yang sama.
Misalnya. Tombol preferensi sederhana dapat diaktifkan atau dinonaktifkan dari dua tempat berbeda:
/ myaccount / toggleNotification
/ dashboard / toggleNotification
jadi haruskah kita memiliki dua pereduksi yang ditulis dengan konten yang sama di
reduksi / notifikasi.js
cc: @ samit4me , @philholden


Hanya pada pemikiran lain, saya pikir ini adalah ide yang bagus, memiliki dua atau lebih reduksi dalam sebuah file yang melakukan pekerjaan yang sama dengan nama tindakan yang berbeda. Ini adalah bagaimana dengan hanya melihat peredam kita dapat memahami bahwa dari berapa banyak tempat yang berbeda keadaan tertentu sedang dimodifikasi.

Bagaimanapun, akan sangat senang mendengar dari para ahli. Terima kasih.

@ivks : beberapa pemikiran di sini.

Pertama, Anda dapat mengirimkan tindakan yang sama dari berbagai tempat dalam aplikasi.

Kedua, Anda pasti dapat memiliki peredam yang sama yang mendengarkan beberapa jenis tindakan, dan menanganinya dengan cara yang sama.

Ketiga, aspek "relasi 1: 1" adalah tentang kemampuan memiliki beberapa pengurang irisan yang mendengarkan tindakan yang sama, dengan masing-masing memperbarui bit statusnya secara independen. Ya, sering kali mungkin hanya ada satu peredam yang peduli tentang tindakan tertentu, tetapi memiliki beberapa peredam yang merespons adalah kasus penggunaan yang dimaksudkan untuk Redux.

@tokopedia

Kedua, Anda pasti dapat memiliki peredam yang sama yang mendengarkan beberapa jenis tindakan, dan menanganinya dengan cara yang sama.

Saya sebenarnya menggunakan redux-actions, dan tidak tahu itu memiliki metode utilitas gabunganAction yang akan melakukan tugas itu. Baru saja menemukannya dan pernyataan Anda di atas menyebutkan hal yang sama. (seharusnya lebih jelas, maaf)
Terima kasih banyak sudah membalas.

Menurut saya, Ducks tidak mendefinisikan dengan benar di ActionTypes:

HARUS memiliki jenis tindakan dalam bentuk npm-module-or-app / reducer / ACTION_TYPE

Alasannya adalah satu tindakan dapat diikuti oleh lebih dari satu pereduksi. Seperti yang dikatakan @mherodev , const ACTION = 'app/feature/ACTION'; lebih masuk akal, selain itu saya ingin menambahkan skema untuk tindakan: const ACTION = 'action://app/feature/ACTION'; .

Mengapa tidak hanya menggunakan bilangan bulat inkremental secara global untuk mengidentifikasi jenis tindakan? misalnya

let id = 0

function generateActionType (label /* for readability */) {
  id++
  return `app/feature/${id}/${label}`
}

Pikirkan tentang ini sedikit, untuk memastikan kami tidak bentrok dengan pengembang lain, kami menulis aturan lint, yang melihat ke dalam direktori (di mana kami memiliki semua reduksi dan setiap reduksi memiliki jenis tindakannya sendiri sebagai konstanta)

Kami berencana melakukan lint sehingga melaporkan pelanggaran jika ada dua konstanta dengan nilai yang sama.

Jika ada saran, beri tahu saya :)

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

captbaritone picture captbaritone  ·  3Komentar

ms88privat picture ms88privat  ·  3Komentar

benoneal picture benoneal  ·  3Komentar

jbri7357 picture jbri7357  ·  3Komentar

CellOcean picture CellOcean  ·  3Komentar