M
M
mix-92019-09-14 11:56:44
JavaScript
mix-9, 2019-09-14 11:56:44

What should be contained in the reducer or where should the functionality be stored?

Good day. React native app with redux. There is a set of actions. There is a set of gearboxes. And there is a function that causes state changes, that is, "action". Everything seems to be clear here.

the code
export const endOrderCreateAction = (dispatch, orderStatus) => {
    return {
        type: END_ORDER_CREATE,
  orderStatus: orderStatus
    }
};
.........
const orderReducer = (state = {data: [], loading: false}, action) => {
  switch(action.type) {
    case END_ORDER_CREATE:
      return {...state, loading: true};
...........
fetch().then(r => dispatch(endOrderCreateAction(dispatch, r)));

But then it became necessary to do several actions after the function was worked out, to change the states several times accordingly. In a specific example with an order, you need to 1) remove the loading animation 2) display a success message 3) add "my orders" to the list. This can be done in two places: the reducer and the state changing function.
in the second case, redrawing several times.
fetch().then(r => {
dispatch(endOrderCreateAction(dispatch, r));
dispatch(stopLoadingAction(dispatch, r));
....
});

In the first case, we get a mess of states,
const orderReducer = (state = {data: [], loading: false}, action) => {
  switch(action.type) {
    case END_ORDER_CREATE:
                ..........
const loadingReducer = (state = {data: [], loading: false}, action) => {
  switch(action.type) {
    case END_ORDER_CREATE:
    case END_USER_LOADING:
    case END_SECTION_LOADING:
                ..........
// одно изменение состояния ловят сразу несколько редукторов

or
const orderReducer = (state = {data: [], loading: false}, action) => {
  switch(action.type) {
    case END_ORDER_CREATE:
                    return {...state, loading: false} 
// собираем итоговый state 
state = {
loading: orderReducer.loading || sectionReducer.loading || userReducer.loading
}

How to do it right?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
N
Nick, 2019-09-22
@DragonSpirit

In general, there are several solutions.
As an option, to start with, use one loading field for the store and call a separate action before network calls, for example

So
// todo/actions.js
export const getTodos = (dispatch) => () => {
  dispatch({ type: 'GET_TODOS_REQUEST' });
  return fetch('/api/v1/todos')
    .then((todos) => dispatch({ type: 'GET_TODOS_SUCCESS', payload: todos })
    .catch((error) => dispatch({ type: 'GET_TODOS_FAILURE', payload: error, error: true });
};

// todo/reducer.js
const initialState = { todos: [] };
export const todoReducer = (state = initialState, action) => {
  switch(action.type) {
    case 'GET_TODOS_REQUEST': 
      return { ...state, isFetching: true };
    case 'GET_TODOS_SUCCESS': 
      return { ...state, isFetching: false, todos: action.payload };
    case 'GET_TODOS_FAILURE': 
      return { ...state, isFetching: false, errorMessage: action.payload.message };
    default: 
      return state;
  }
};

To avoid a bunch of re-renders, you should use selectors in containers.
If there are several identical entities that need the same type of action, then you can use the duck approach

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question