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 munication 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 ponent, 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 ponent'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];
};
// ponent
// -------------------------
const ponent = (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 plexity 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?
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 munication 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 ponent, 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 ponent'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];
};
// ponent
// -------------------------
const ponent = (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 plexity 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?
Share Improve this question asked Nov 8, 2019 at 15:39 user210757user210757 7,40619 gold badges76 silver badges121 bronze badges 6- It's the same pattern, but used locally. So it is different since it's no longer globally accessible. If the pattern feels like too much boilerplate, you could fall back to Class ponents, hooks are not the solution to everything. Class ponents aren't deprecated. – Emile Bergeron Commented Nov 8, 2019 at 16:24
- @EmileBergeron I'm fine with the boilerplate and am loving hooks, just haven't seen alot of examples of what I'm doing basically making local state redux. Seems like more examples of just putting fetch right in the ponents – user210757 Commented Nov 22, 2019 at 22:11
- Are you basically asking why would you use just React when React and Redux work fine? Or are you asking why use Redux when React works just fine by itself? – Galupuf Commented Nov 25, 2019 at 20:18
- @Galupuf I guess I'm asking if I'm using hooks and local state correctly by using it the exact same way I'd use redux – user210757 Commented Nov 27, 2019 at 15:07
-
1
Yes you are :) Keep in mind that
useReducer()
was actually inspired by redux and you should use it if "you have plex state logic that involves multiple sub-values or when the next state depends on the previous one." Keep in mind you can also useuseState()
, but it just depend on your use case. – Galupuf Commented Nov 27, 2019 at 15:13
4 Answers
Reset to default 2It really boils to three things for me:
- Whether you need Redux's middleware, logging features etc or not
- How much you care about future stability
- 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 plexity 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 plexity 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 ponents framework from Salesforce.
The point being that it keeps state management and view logic in separate libraries.
React being 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 being 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).
Advantages of storing the state in Redux:
- You can access and modify it globally
- It persists even after your ponent is unmounted
Advantages of storing the state in the ponent:
- You can have multiple ponents with different values in the state, which may be something you want
- ...Or you could even have multiple hooks of the same type in one ponent!
- You don't need to switch between files. Depending on how your code is organized, Redux can be split into 3 files + 1 file for the ponent which uses it - while this can help keep your code well-structured for plex use cases, it can be an overkill for keeping track of a simple state. Having to switch between multiple files to work on one ponent can reduce your productivity (I don't like having to keep track of 4 tabs in my IDE for every feature I work on).
- (Also, hooks are new and cool.)
So, use Redux if:
- You need to share state between multiple ponents (or plan to in the future)
- You need to keep state even when the ponent that uses it is unmounted
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!
No, you don't have to.
From my point of view, if only as a state management lib, Redux can be replaced by Hooks (useReducers
ect) + local/shared state.
Redux es before hooks and our app has been implemented by Redux, definitely you don't have the need to replace it.
We can plan to use hooks + shared state as an alternative in our new projects.
I did met with three situations, which are:
- Redux ONLY;
- Hooks ONLY;
- Redux + Hooks;
All of them worked fine.
It's the dilemma that we're in the transition of Redux and Hooks. Hooks are made in a way not to replace redux but it can if you want to.
So in future, you can use any of those, depending on you use case.
Hope it helps.
Redux for global state management. Custom hooks to even replace selector and dispatch and other business logic or api from ponents to hooks, hence dumb ponents as much as possible
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744916371a4600858.html
评论列表(0条)