Hello, there!
I’ve seen a lot of more articles about React and Redux combination and most of them explaining how to connect these solutions and basic usage. But lets imagine that We have a project a bit larger than the regular todo-list example. Our project have a store with a lot of different modules and hundreds actions.
I would like to show You how I created my own solution without any built-in solutions or packages.
The most trivial and easy solution is a providing a store state and actions via props. I won’t describe a full example here You know how it works.
connect(mapStateToProps, (dispatch: Dispatch<AnyAction>) =>
bindActionCreators({<actions_object>}, dispatch))(MyComponent)
Pros: Easy to use, fast solution, reactive as well.
Cons: Need to provide each store state item or action manually to a child component(Of course, You may connect each component to the store but there will be a very high-weight components).
Latest versions of Redux offers us several hooks for accessing to store like:
useStore — get the store instance directly;useDispatch — get a dispatch function;useSelector — build a reactive getter from store;Let’s start with a defining of what we need. I would like to make a hook which will allow getting any state module, property as reactive and getting any action. It should support TypeScript as well, obviously.
Actually, we have to remember about performance and convenience. So, let’s see how it should be used:
const { someState, someAction } = ourHook() // someState and someAction provide types automatically
Let’s start with creating of custom hook.
const useMappedStore = () => {
return {...state, ...actions}; // Typed
}
Firstly, I have to map the store actions, make them dispatchable and return to component. It could be achieved with the built-in redux function bindActionCreators(actionsObj, dispatch).
Secondly, need to get store state reactively. We may achieve it with hooks above. But how we can get a state dynamically and reactively?
Let’s use a one interest instrument named as Proxy.
export const useMappedStore = () => {
const store = useStore<AppState>();
const dispatch = useDispatch();
const storeStateAccessor: AppState = store.getState();
const storeStateAccessorProxy = new Proxy<AppState>(storeStateAccessor, {
get(target, p, receiver) {
return useSelector((state) => state[p]);
}
});
return {
...storeStateAccessorProxy,
...bindActionCreators(getActions(), dispatch)
};
};
As you can see I used a proxy to creating a selector hook dynamically. Any store state property will be called when component will be created. Pay attention we are not breaking hooks rules.
If We have to support old browsers We could use Object.defineProperty as well.
I know NPM has a thousands redux helper packages and I just wanted to show you how developer could implement it manually.
Thanks for reading!