Dispatch & states by Redux Hooks with ease
This post hasn't been updated for 5 years
Since the release of React-Redux version 7.1
in (11th June 2019), Redux Hooks
is now can be used properly.
Redux Hooks makes it easy to use each component and dispatch
, state
without using connect()
.
Here is my sample code, the Action
, Reducer
part is omitted.
A component that simply increases or decreases the counter value.
import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { incrementAction, decrementAction } from "./Actions";
const counterSelector = state => state.counter;
const Counter = props => {
// You can get the dispatch attached to the store with useDispatch.
const dispatch = useDispatch();
// You can get the state of the store using useSelector
const counter = useSelector(counterSelector);
return (
<>
<p> count: {counter} </p>
<button onClick={dispatch(incrementAction())}>increment</button>
<button onClick={dispatch(decrementAction())}>decrement</button>
</>
);
};
If we don't unse useSelector
and useDispatch
, the source code will be like this:
import React from "react";
import { connect } from 'react-redux'
import { incrementAction, decrementAction } from "./Actions";
const counterSelector = state => state.counter;
const CounterComponents = props => {
return (
<>
<p> count: {props.counter} </p>
<button onClick={props.increment}>increment</button>
<button onClick={props.decrement}>decrement</button>
</>
);
};
const mapStateToProps = state => ({
counter: counterSelector(state)
});
const mapDispatchToProps = dispatch => ({
increment: () => dispatch(incrementAction()),
decrement: () => dispatch(decrementAction())
});
const Counter = connect(
mapStateToProps,
mapDispatchToProps
)(CounterComponents);
If we use Redux Hooks, we can see that the connect part is gone, and the code is pretty clean.
useSelector()
If you want to get the state
from the store
, call useSelector()
. Specify a selector
function that takes a state
as an argument of useSelector
.
const counterSelector = (state) => state.counter
const Counter = (props) => {
const counter = useSelector(counterSelector)
return <div>{counter}</div>
}
useDispatch()
You can get the dispatch
attached to the store with useDispatch
.
const Counter = (props) => {
const dispatch = useDispatch()
return (
<>
<button onClick={()=> {dispatch({ type: "INCREMENT_COUNTER" })}}>increment</button>
<button onClick={()=> {dispatch({ type: "DECREMENT_COUNTER" })}}>decrement</button>
</>
)
}
When passing dispatch
to a child component, it is recommended use useCallback
to memorize. This is to avoid unnecessary re-rendering of child components due to parent re-rendering.
import React, { useCallback } from 'react'
import { useDispatch } from 'react-redux'
export const CounterComponent = ({ value }) => {
const dispatch = useDispatch()
const incrementCounter = useCallback(
() => dispatch({ type: 'increment-counter' }),
[dispatch]
)
return (
<div>
<span>{value}</span>
<MyIncrementButton onIncrement={incrementCounter} />
</div>
)
}
export const MyIncrementButton = React.memo(({ onIncrement }) => (
<button onClick={onIncrement}>Increment counter</button>
))
Important Note
Unlike using mapStateToProps
, useSelector
has some problems.
Problems can arise especially when useSelector()
relies on props
. Reference: Usage Warnings
Each time dispatch
is executed, useSelector()
is also executed. At this time, there is no guarantee that props
is up-to-date.
Example
dispatch()
is executed and the component'suseSelector()
is executed.- The parent component is rerendered and
props
are passed to the component. - If
useSelector()
is executed beforeprops
is passed, an inconsistency will occur if the selector function depends onprops
.
The solutions are as follows.
- The
selector
function does not useprops
. - Use carefully if the
selector
function depends onprops
andprops
changes orstate
data is deleted based on astate
change. Instead of using something likestate.todos[props.id].name
, first check the existence of data withstate.todos[props.id]
, and then call ittodo.name
.
Managing
How to prepare simple global state
by combination of useContext
and useReducer
has been proposed since React Hooks was officially announced.
I think using Redux
is easy and pretty attractive.
I've been using it from v7.1.0-alpha.5
, and it is quite handy.
Though i needed to configure it with care
Summary
That's all I want to share for the Redux Hooks, which has been officially released since React Redux 7.1.
Using react-starter-kit
can further reduce the amount of code written and make development easier.
All Rights Reserved