Búsqueda de sitios web

reactjs - ¿Redux una mejor manera de escribir reducers?


Creo que Redux tiene mucho valor, sin embargo, el problema principal para mí radica en cómo se escriben los reducers hoy en día:

const addToDoReducer = (state, action) => {
    switch (action.type) {
        case ADD_TODO:
            return Object.assign({}, state, {
                todos: todos(state.todos, action)
            })
        case TOGGLE_TODO:
            return Object.assign({}, state, {
                todos: todos(state.todos, action)
            })
        default:
            return state
    }
}
  • los reducers son demasiado genéricos (literalmente puedes escribir un reducer inflado que maneje todo tipo de diferentes acciones y fácilmente crear un desastre) si nada más, esto rompe el principio de responsabilidad única
  • la declaración switch impone efectos secundarios de mantenimiento como que los cambios en un caso podrían romper otros casos (por ejemplo, código que ya funciona)
  • siempre repetido "default: return state" (falla DRY)
  • todos los reductores siempre son invocados (llamar a funciones para no hacer nada está simplemente mal)

... al final, los reductores se convierten en el punto débil/collarín del proyecto

P: ¿Hay una mejor manera/opción de escribir un reductor que:

  • se invoca solo para una acción específica (basada en el tipo de objeto de acción)
  • elimina la instrucción switch

algo más como esto:

const addToDoReducer = (state:toDoState, action:addAction) =>
{
    return { ...state, toDos: [...state.toDos, action.toDoObject] };
}

¿O hay alguna biblioteca que ya haga esto?

Respuesta #1

Por favor, lea la página de documentación "Reduciendo Código Repetitivo" para ver ejemplos de cómo puede escribir sus propias utilidades de reductor, como una función que toma una tabla de consulta de tipos de acción a funciones de reductor específicas para cada tipo. Específicamente:

function createReducer(initialState, handlers) {
  return function reducer(state = initialState, action) {
    if (handlers.hasOwnProperty(action.type)) {
      return handlers[action.type](state, action)
    } else {
      return state
    }
  }
}

La sección de documentación "Structuring Reducers" también ofrece instrucciones e ideas sobre formas de organizar la lógica de tus reducers.

Para más información, por favor vea:

  • La entrada del FAQ de Redux sobre "llamar a todos los reducers" y el rendimiento
  • La entrada de preguntas frecuentes de Redux sobre el uso de declaraciones switch
  • Mi publicación de blog El Tao de Redux, Parte 2 - Práctica y Filosofía, que discute específicamente el hecho de que si usas sentencias switch y cómo escribes la lógica de tu reducer depende completamente de ti
  • La lista del catálogo de complementos de Redux de bibliotecas de utilidades de reductores

Recuerda: Redux llama a tu función reductora raíz, que es código que tú has escrito. Cómo ese reductor realiza su trabajo es tu elección. Si no te gustan las declaraciones switch, no las escribas. Si encuentras el código repetitivo, escribe funciones fábrica.

Respuesta #2

Puedes crear tal módulo:

// createReducer.js
export default (initiateState, reducerMap) => {
    return function(state, action) {
        const currentState = state !== undefined ? state : initiateState;
        const handler = reducerMap[action.type];
        return handler ? handler(currentState, action) : currentState;
    };
};

Y luego, configure el estado inicial en el primer argumento y almacene la lista de acciones como un objeto. Por ejemplo:

import createReducer from './createReducer';

const STORE_TEST_MODULE = 'STORE_TEST_MODULE';

export default createReducer(
    // Initial state
    {
        test: null,
    },   
    {
        // Custom action #1
        [STORE_TEST_MODULE]: (state, action) => {
            return {...state, ...action.payload};
        },

        // Custom action #2
        'CLEAR_TEST': (state, action) => {
            return {test: null};
        },
    }
);

Artículos relacionados