With Redux, we can use it to store data in a central location in our JavaScript app. It can work alone and it’s also a popular state management solution for React apps when combined with React-Redux.
In this article, we’ll look at the new hooks React-Redux Hooks API.
Using the useSelector Hook in a React Redux App
The hooks API consists of the useSelector
, useDispatch
, and useStore
hooks.
The useSelector
hook takes a selector
function to select data from the store and another function equalityFn
to compare them before returning the results and determine when to render if the data from the previous and current state are different.
The call takes the following format:
const result : any = useSelector(selector : Function, equalityFn? : Function)
It’s equivalent to mapStateToProps
in connect. The selector will be called with the entire Redux store state as its only argument.
The selector function may return any value as a result, not just an object. The return value of the selector will be used as the return value of the useSelector
hook.
When an action is dispatched, useSelector
will do a shallow comparison of the previous selector result value and the current one.
The selector
function doesn’t receive an ownProps
argument. Props can be used through closure or by using the curried selector.
We may call useSelector
multiple times within a single function component. Each call creates an individual subscription to the Redux store. React update batching behavior will cause multiple useSelector
s in the same component to return new value should only return in a single re-render.
Equality Comparisons and Updates
The provided selector function will be called and its result will be returned from the useSelector
hook. A cached result may be returned if the selector is run and returns the same result.
useSelector
only forces a re-render if the selector result appears to be different than the last result.
This is different from connect
, which uses shallow equality checks on the results of mapState
calls to determine if re-rendering is needed.
If we want to retrieve multiple values from the store, we can call useSelector
multiple times with each call returning a single field value, use Reselect or a similar library to create a memoized selector that returns multiple values in an object but returns a new object when one of the values is changed.
We can also use the shallowEqual
function from React-Redux as the equalityFn
argument to useSelector
.
For example, we can use useSelector
as follows:
import React from "react";
import ReactDOM from "react-dom";
import { Provider, useSelector, useDispatch } from "react-redux";
import { createStore } from "redux";
function count(state = 0, action) {
switch (action.type) {
case "INCREMENT":
return state + 1;
case "DECREMENT":
return state - 1;
default:
return state;
}
}
const store = createStore(count);
function App() {
const count = useSelector(state => state);
const dispatch = useDispatch();
return (
<div className="App">
<button onClick={() => dispatch({ type: "INCREMENT" })}>Increment</button>
<button onClick={() => dispatch({ type: "DECREMENT" })}>Decrement</button>
<p>{count}</p>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
rootElement
);
In the code above, we created the store as usual. Then in the App
component, we used the useSelector
hook to get the count
by passing in the state => state
function.
Then we get the dispatch
function to useDispatch
.
We can use the second argument of the useSelect
hook as follows:
import React from "react";
import ReactDOM from "react-dom";
import { Provider, useSelector, useDispatch, shallowEqual } from "react-redux";
import { createStore } from "redux";
function count(state = 0, action) {
switch (action.type) {
case "INCREMENT":
return state + 1;
case "DECREMENT":
return state - 1;
default:
return state;
}
}
const store = createStore(count);
function App() {
const count = useSelector(state => state, shallowEqual);
const dispatch = useDispatch();
return (
<div className="App">
<button onClick={() => dispatch({ type: "INCREMENT" })}>Increment</button>
<button onClick={() => dispatch({ type: "DECREMENT" })}>Decrement</button>
<p>{count}</p>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
rootElement
);
React-Redux has a shallowEqual
function to compare data to determine when to update data. We can also define our own function to compare the previous and current state to determine updates.
Conclusion
We can use the useSelector
hook to get the data from the Redux store in a React component.
It takes 2 arguments. The first argument is a function that returns the state, and the second argument is a function that checks if the previous and current state are equal to determine when to update.