Here I was trying to implement the same login routine with Redux and Context Provider. Both doing it in the pretty same way and with similar syntax.
Provider
First of all, you need to provide access to the state. Redux and Context doing it with a component called Provider
.
Redux Provider
accepts prop called store
, with current state and rules on how to update it.
const store = createStore(/* rules to set store */)
<Provider store={store}>
<App />
</Provider>
Context Provider
accepts value which can be passed down to Consumer
. But you also free to rewrite this Provider
to customize it (this is actually what we want).
<Provider value={/* some value, optional */}>
<App />
</Provider>
Consumer
Get
Redux provides useSelector
hook to get value from the state you interested in.
const { isLoggedIn } = useSelector(state => ({
isLoggedIn: state.isLoggedIn
}));
Context provides useContext
hook for this.
// import context as AuthContext
const { isLoggedIn } = useContext(AuthContext);
Set
You can also update the state.
Redux provides you with a dispatch method that triggers store updates. Ofc, you need to write these rules yourself within reducer.
const dispatch = useDispatch();
dispatch({
type: SET_LOGIN_STATUS,
isLoggedIn: true
});
With React Context you need to implement update method within Provider
and then use it via same useContext
hook;
// import context as AuthContext
const { login } = useContext(AuthContext);
login();
Business Logic
Context Provider
Here is Context Provider
implementation with state and functions to update it. In the end, you need to pass it further within value
property to make it available to the Consumer
. Looks pretty sharp and simple to me.
Check for full code for Context on Codesandbox.
export const AuthContext = React.createContext(null);
const initialState = {
isLoggedIn: false,
isLoginPending: false,
loginError: null
}
export const ContextProvider = props => {
const [state, setState] = useState(initialState);
const setLoginPending = (isLoginPending) => setState({
...state,
isLoginPending
});
const setLoginSuccess = (isLoggedIn) => setState({
...state,
isLoggedIn
});
const setLoginError = (loginError) => setState({
...state,
loginError
});
const login = (email, password) => {
setLoginPending(true);
setLoginSuccess(false);
setLoginError(null);
fetchLogin( email, password, error => {
setLoginPending(false);
if (!error) {
setLoginSuccess(true);
} else {
setLoginError(error);
}
})
}
return (
<AuthContext.Provider
value={{
state,
login,
logout,
}}
>
{props.children}
</AuthContext.Provider>
);
Redux Store
With Redux you need to write a bit more lines of code. And add thunk
middleware if you want to make it work async, and most times probably you are. There are a lot of articles around on how to do it, so I will skip full codebase, you can check full code for Redux on Codesandbox.
Outro
So it looks like this Context and Redux hooks can be used interchangeably, and also it can be easily used together. Like for example, Redux for the main store and Context for some more local state management. So, you won't put all your data in same store which can become very messy at the end.
Top comments (0)