javascript - bootstrap - Redux: organizando contenedores, componentes, acciones y reductores
popover js (1)
La pregunta:
¿Cuál es la mejor práctica recomendada y más fácil de mantener para organizar contenedores, componentes, acciones y reductores en una aplicación grande de React / Redux ?
Mi opinión:
Las tendencias actuales parecen organizar garantías reductoras (acciones, reductores, sagas ...) alrededor del componente contenedor asociado. p.ej
/src
/components
/...
/contianers
/BookList
actions.js
constants.js
reducer.js
selectors.js
sagas.js
index.js
/BookSingle
actions.js
constants.js
reducer.js
selectors.js
sagas.js
index.js
app.js
routes.js
Esto funciona genial! Aunque parece haber un par de problemas con este diseño.
Los problemas:
Cuando necesitamos acceder a actions
, selectors
o sagas
desde otro contenedor parece un antipatrón. Digamos que tenemos un contenedor global /App
con un reductor / estado que almacena la información que utilizamos en toda la aplicación, como categorías y enumerables. Siguiendo con el ejemplo anterior, con un árbol de estado:
{
app: {
taxonomies: {
genres: [genre, genre, genre],
year: [year, year, year],
subject: [subject,subject,subject],
}
}
books: {
entities: {
books: [book, book, book, book],
chapters: [chapter, chapter, chapter],
authors: [author,author,author],
}
},
book: {
entities: {
book: book,
chapters: [chapter, chapter, chapter],
author: author,
}
},
}
Si queremos usar un selector
del contenedor /App
dentro de nuestro contenedor /BookList
necesitamos recrearlo en /BookList/selectors.js
(¿seguramente está mal?) O importarlo desde /App/selectors
(¿será siempre el EXACTO? mismo selector ...? no). Ambos estos appraoches me parecen poco óptimos.
El mejor ejemplo de este caso de uso es Autenticación (ah ... auth nos encanta odiarte) ya que es un modelo MUY común de "efecto secundario". A menudo necesitamos acceder /Auth
sagas, acciones y selectores por toda la aplicación. Es posible que tengamos los contenedores /PasswordRecover
, /PasswordReset
, /Login
, /Signup
... ¡De hecho, en nuestra aplicación nuestro /Auth
contianer no tiene ningún componente real!
/src
/contianers
/Auth
actions.js
constants.js
reducer.js
selectors.js
sagas.js
Simplemente contiene todas las garantías de Redux para los diversos contenedores de autenticación a menudo no relacionados mencionados anteriormente.
Yo personalmente uso la propuesta packs-modular-redux .
No es la manera recomendada "oficial", pero funciona muy bien para mí. Cada "pato" contiene los actionTypes.js
, actionCreators.js
, sagas.js
, sagas.js
y selectors.js
. No hay dependencia de otros patos en estos archivos para evitar la dependencia cíclica o el círculo de pato , cada "pato" contiene solo la lógica que debe administrarse.
Luego, en la raíz, tengo un components
y una carpeta de containers
y algunos archivos raíz:
components/
carpeta contiene todos los componentes puros de mi aplicación
containers/
carpeta contiene contenedores creados a partir de componentes puros arriba. Cuando un contenedor necesita un selector
específico que involucre muchos "patos", lo escribo en el mismo archivo donde escribí el componente <Container/>
, ya que es relativo a este contenedor específico. Si el selector
se comparte por varios contenedores, lo creo en un archivo separado (o en un HoC que proporciona estos accesorios).
rootReducers.js
: simplemente expone los reductores de raíz combinando todos los reductores
rootSelectors.js
expone el selector de raíz para cada porción de estado; por ejemplo, en su caso podría tener algo como:
/* let''s consider this state shape
state = {
books: {
items: { // id ordered book items
...
}
},
taxonomies: {
items: { // id ordered taxonomy items
...
}
}
}
*/
export const getBooksRoot = (state) => state.books
export const getTaxonomiesRoot = (state) => state.taxonomies
Nos permite "ocultar" la forma del estado dentro de cada archivo selectors.js
patos. Como cada selector
recibe el estado completo dentro de sus patos, simplemente tiene que importar el rootSelector
correspondiente dentro de sus archivos selector.js
.
rootSagas.js
compone todas las sagas dentro de tus patos y administra un flujo complejo que involucra a muchos "patos".
Entonces en tu caso, la estructura podría ser:
components/
containers/
ducks/
Books/
actionTypes.js
actionCreators.js
reducers.js
selectors.js
sagas.js
Taxonomies/
actionTypes.js
actionCreators.js
reducers.js
selectors.js
sagas.js
rootSelectors.js
rootReducers.js
rootSagas.js
Cuando mis "patos" son lo suficientemente pequeños, a menudo me salteo la creación de la carpeta y escribo directamente un ducks/Books.js
o ducks/Taxonomies.js
con todos estos 5 archivos ( actionTypes.js
, actionCreators.js
, actionCreators.js
, selectors.js
, sagas.js
) fusionados.