Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redux vs custom hook

Tags:

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?

like image 880
user210757 Avatar asked Nov 08 '19 15:11

user210757


1 Answers

It really boils to three things for me:

  1. Whether you need Redux's middleware, logging features etc or not
  2. How much you care about future stability
  3. Personal taste

Redux offers more than merely state management.
Offloading context handling to Redux is a big plus for me looking forward into the future.
If your application is very data-centric, I would not omit redux-devtools and other middleware (I personally like redux-observable).
When your app grows in complexity you will want to find out about corrupt state updates and state that gets triggered multiple times unexpectedly.
But then again, only you can assess the complexity of your own app and where it will be headed towards in the future.

The rest of this post is 'personal taste', but I'll add it.

Personally I like using Redux for a few different reasons than before mentioned.
I used Redux without using React at all not even so long ago, and also with a framework which nobody probably heard about, which is the Lightning web components framework from Salesforce.
The point being that it keeps state management and view logic in separate libraries.
React becoming a Swiss army knife is something I'm not really in favour of, personally.
React's core strength for me was that it was a view library featuring the virtual DOM with a clear purpose whereas now... well where is the border between it just becoming an opinionated framework?
Using React hooks is not imposed, but then again it sort of is.
If you use React, you will use all of it, this question bringing tribute to this conclusion.

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

So you refactor Redux to the useReducer hook and then wonder, why did I need this? If you ask then you probably didn't.
Maybe that is just the answer to your question.
Reducer functionality just moved from a state management library to a view library (or is it?). Cool (I guess).

like image 168
html_programmer Avatar answered Oct 12 '22 23:10

html_programmer