uso usar reducer react que mapstatetoprops entendiendo como avanzado acciones javascript reactjs redux react-redux

javascript - usar - redux que es un reducer



Redux: ¿Solo se permiten llamadas sincrónicas desde las funciones del reductor? (4)

Tengo una aplicación de reactJs y ahora estoy aprendiendo a usar Redux para usarlo como implementación de Flux.

Creé una tienda y creé mi primera función de reducción pero ahora tengo algunas preguntas que me vienen a la mente, por favor ayúdame a entender.

Como pueden ver, tengo una acción llamada ''FIND_PRODUCTS'' que básicamente es obtener datos de un servicio de back-end. Para llamar a este servicio back-end utilizo básicamente una llamada ajax asincrónica, así que básicamente el problema al que me enfrento es que el estado se devuelve desde la función reductora antes de que mi llamada backend haya finalizado, entonces el estado no se actualiza correctamente y los suscriptores la tienda está obteniendo datos incorrectos. Este problema se resuelve si cambio a una llamada síncrona, pero entonces, la primera advertencia que recibo es que se debe evitar la llamada síncrona porque puede disminuir la experiencia del usuario (rendimiento).

Entonces mi pregunta, ¿podemos solo obtener datos de forma sincrónica desde una función reductora? ¿Los datos de búsqueda ocurren en la función de reducción o hay otra forma de hacerlo? si es así, ¿qué es?

¿Este modelo de reducción de tener un solo árbol de objetos para mantener el estado se adapta bien a grandes aplicaciones? ¡Si tengo 1000 acciones, el cambio en mi función de reductor será enorme! ¿Cómo podemos evitar eso?

¡¡Gracias!!

const initialState = { availableLocales: [{text: ''En''}, {text: ''Es''}, {text: ''Fr''}], selectedLocale: ''En'', translations: i18n.getTranslations(), products: [] }; const reducer = (state = initialState, action = {type: ''NONE''})=> { //To make the reducer a pure function deepFreeze(state); deepFreeze(action); switch (action.type) { case ''SWITCH_LOCALE'': let newState = Object.assign({}, state, { selectedLocale: action.locale, translations: i18n.getTranslations(action.locale) }); return newState; case ''FIND_PRODUCTS'': let newState = Object.assign({}, state, { products:ProductHelper().findProductsByProductType(action.productType) }); return newState; default: return state } return state; } // Create a Redux store holding the state of your app. // Its API is { subscribe, dispatch, getState }. const store = createStore(reducer); // You can subscribe to the updates manually, or use bindings to your view layer. store.subscribe(() => console.log(store.getState()) ); export default store;


Considera esto:

Crea el archivo actions.js y exporta las funciones de acciones como esta:

import * as types from ''../constants/action_types''; import * as api from ''../utils/api'' export function something1(someId){ return (dispatch) => { dispatch({type: `${types.SOMETHING1}_PENDING`}); api.getSomething(someId) .then((res) => { dispatch({ type: `${types.SOMETHING1}_SUCCEEDED`, somethings: res.body }); .catch((err) => { dispatch({ type: `${types.SOMETHING1}_FAILED`, errors: err.body }) }); } } export function something2(someOtherId){ return (dispatch) => { dispatch({type: `${types.SOMETHING2}_PENDING`}); api.getSomething2(someOtherId) .then((res) => { dispatch({ type: `${types.SOMETHING2}_SUCCEEDED`, otherThings: res.body }); .catch((err) => { dispatch({ type: `${types.SOMETHING2}_FAILED`, errors: err.body }) }); } }

Entonces el estado solo cambia cuando tienes los datos

A continuación, separe sus reductores en archivos separados y cree un archivo para exportarlos a todos de la misma manera que reducers / index.js:

export { default as reducer1 } from ''./reducer1''; export { default as reducer2 } from ''./reducer2''; export { default as reducer3 } from ''./reducer3''; export { default as reducer4 } from ''./reducer4'';

Luego configura tu tienda así:

configure_store.js

import { createStore, combineReducers, applyMiddleware } from ''redux''; import thunk from ''redux-thunk''; import * as reducers from ''../reducers''; const rootReducer = combineReducers(reducers); const createStoreWithMiddleware = applyMiddleware(thunk)(createStore); export default function configureStore(initialState) { return createStoreWithMiddleware(rootReducer, initialState); }

Finalmente agregue esto a su raíz:

import configureStore from ''../store/configure_store''; const store = configureStore(); class Root extends Component { render() { return ( ... <Provider store={ store } > ... </Provider> ); } } export default Root;


Como decía la documentación redux , los reductores deberían ser funciones puras, por lo que no deberían hacer peticiones ajax.

Una mejor forma de hacerlo es utilizar el middleware redux-thunk , que le permite llamar al dispatch varias veces en una acción.

Entonces, en tu ejemplo, haces algo como esto:

// definition of action creator function loadProducts(productType) { return {type: ''FIND_PRODUCTS'', productType: productType} } ... // calling dispatch of your action dispatch(loadProducts(productType));

Pero con redux-thunk tu creador de acciones será algo como esto:

function loadProducts(productType) { return function(dispatch){ dispatch({type: ''FIND_PRODUCT_STARTED''}); // I don''h know how findProductsByProductType works, but I assume it returns Promise ProductHelper().findProductsByProductType(productType).then(function(products){ dispatch({type: ''FIND_PRODUCT_DONE'', products: products}); }); } }

Y su reductor se convertirá en una función pura:

... case ''FIND_PRODUCTS_DONE'': let newState = Object.assign({}, state, { products: action.products, }); return newState; ...

En este caso, también puede manejar el estado de carga, es decir, establecer el indicador de loading en su estado en verdadero cuando action.type es FIND_PRODUCT_STARTED .

En mi ejemplo, supongo que findProductsByProductType devuelve Promise. En este caso, incluso puede usar redux-promise-middleware sin redux-thunk, hará todo el trabajo por usted:

function loadProducts(productType) { return { type: ''FIND_PRODUCT'', payload: { promise: ProductHelper().findProductsByProductType(productType) } } }


No debe usar ProductHelper () en su reductor para solicitar datos.

En su lugar, debe usar un creador de acciones para enviar una acción que solicite los datos de su API. Su middleware API devolvería la promesa de que al finalizar enviaría un intento de acción con carga para que su reductor consuma y devuelva el siguiente estado.

Te recomiendo que veas el middleware Redux Thunk y Redux API


Primero, NO PUEDE obtener datos en el reductor, porque debe ser puro mediante la definición de reducción. Debería crear un creador de acciones, que capturaría los datos de forma asíncrona y los pasaría a Reducer. Las acciones PUEDEN ser impuras.

Aquí puede leer más http://redux.js.org/docs/advanced/AsyncActions.html

También puede usar middleware como redux-thunk para simplificar esto. https://github.com/gaearon/redux-thunk

En cuanto a la segunda pregunta, puede tener más de un reductor en su aplicación. y que los combine con combineReducers(...) function http://redux.js.org/docs/basics/Reducers.html