javascriptreactjsreduxarchitecturereact-redux

Redux vs custom hook


I learned react and Redux at the same time and went "all in" on Redux; basically all state is stored in Redux. And I followed the standard allIds, byId state shape pattern as detailed here.

My app is very data-centric, it talks to an API, and does alot of CRUD type actions - fetchAll, fetchById, add, update, delete.

The API communication is segregated into a "service layer" module that is its own npm package. All calls to this service layer are in the Redux actions, using redux-thunk.

I've realized there is no need to put most everything in Redux, the data is really needed on a specific component, for example. And I would love to simplify this architecture.

So I began to refactor into a custom hook instead. It seemed since my state shape was more of an object rather than scalar, I should use useReducer rather than useState...

// reducer
// ------------------------- 
const initialState = {
  adding: false,
  updating: false,
  deleting: false,
  error: null,
  items: null
};
const reducer = (state, action) => {
// implementation omitted for brevity. . .
}
const useItemsApi = () => {
  const [state, dispatch] = useReducer(reducer, initialState);

  // wrapped in useCallback because called in component's useEffect
  const fetchItems = useCallback(async (options) => {
    try {
      const resp = apiService.fetchItems(options);
    } catch (err) {
      if(err.status === 401) 
         // send to login screen
      else
         dispatch({type: 'error', payload: err});
    }
  }, [options]);

  // addItem, updateItem, deleteItem, etc...

  const actions = {fetchItems, updateItem, addItem, deleteItem};
  return [state, actions];
};

// component
// ------------------------- 
const component = (props) => {
  const [state, actions] = useItemsApi();
  const {fetchItems, updateItem, addItem, deleteItem} = actions;
  useEffect(() => {
     fetchItems()
  }, fetchItems);

  // omitted for brevity...
}

When I got to setting the state in the reducer for the update action, I realized it would be easier if I used "allIds" and "byId" pattern.

And at this point I thought - how is this any different than using Redux?

It is going to end up looking like almost the exact same code, and I'm losing some power of selectors, but removing the complexity of redux-thunks. And my current redux actions include specific use case actions (special save for item type X, for ex.) so I'd need to find a place for those.

My question is - is there any reason to refactor this to a hook using local state?


Solution

  • Advantages of storing the state in Redux:

    Advantages of storing the state in the component:

    So, use Redux if:

    You might prefer to keep the state in React (hooks or otherwise) in other cases since they simplify your code a bit.

    But that doesn't mean you need to refactor your entire codebase. If you think your code is concise enough and you like the way it is organized, or if you are unsure if you will need the state globally in the future, you can keep it in Redux - there is nothing wrong with that!