React-Redux & Hooks: useSelector() and useDispatch()
Earlier in React, the connect()
method (along with the associated mapStateToProps()
and mapDispatchToProps()
functions) is used to connect a React component to the Redux store in the application. However, with the advent of Hooks, alternatives in the form of useSelector()
and useDispatch()
have become available.
In this tutorial, we will show, with an example, how to implement the useSelector()
and the useDispatch()
hooks in a React function component.
We create directories /redux/reducers
and /redux/actions
which will store two two files inside each.
Inside redux/reducers
, we save the first reducer dog.js
which stores the url of some dog image.
// dog.js
const INITIAL_STATE = {
url: ''
}
export default (state = INITIAL_STATE, action={}) => {
switch(action.type) {
case "SET_DOG_DATA":
return {
...state,
...action.content
};
default:
return state;
}
};
The other reducer, quote.js
, stores a movie quote and the corresponding role. This is the second file stored inside redux/reducers
.
// quote.js
const INITIAL_STATE = {
quote: '',
role: ''
}
export default (state = INITIAL_STATE, action={}) => {
switch(action.type) {
case "SET_QUOTE_DATA":
return {
...state,
...action.content
};
default:
return state;
}
};
There is also an index.js
file inside redux/reducers
where the two reducers are combined into a single reducing function with the help of the combineReducers() function.
// index.js
import { combineReducers } from 'redux';
import dog from './reducers/dog';
import quote from './reducers/quote';
const singleReducer = combineReducers({
dog,
quote
});
export default singleReducer;
The combineReducers()
function produces a single state object, singleReducer
, which is later passed to the function createStore
inside the store.js
file. You may store this file in whichever directory you deem fit, but for the purpose of the example here it is stored in the root directory.
// store.js
import { createStore, applyMiddleware, compose } from 'redux';
import singleReducer from './redux/index';
import thunk from 'redux-thunk';
const store = createStore(
singleReducer,
compose (applyMiddleware(thunk),
window.devToolsExtension? window.devToolsExtension(): f => {return f})
);
export default store;
The other /redux/actions
directory is created for storing actions. Actions include type value. The first action creator for dispatching dog image to the store is inside dog.js
.
// dog.js
import axios from 'axios';
const setDogData = (content) => {
return {
type: "SET_DOG_DATA",
content
}
}
const fetchDogImage = () => {
return (dispatch) => {
return axios.get('https://dog.ceo/api/breeds/image/random').then(response => {
if(response.status === 200) {
dispatch(
setDogData({
url: response.data.message
})
)
}
});
}
}
export {
setDogData,
fetchDogImage
}
And the other action creator for dispatching movie quote and the corresponding role is inside quote.js
.
// quote.js
import axios from 'axios';
const setQuoteData = (content) => {
return {
type: "SET_QUOTE_DATA",
content
}
}
const fetchQuote = () => {
return (dispatch) => {
return axios.get('https://movie-quote-api.herokuapp.com/v1/quote/').then(response => {
if(response.status === 200) {
dispatch(
setQuoteData({
quote: response.data.quote,
role: response.data.role
})
)
}
});
}
}
export {
setQuoteData,
fetchQuote
}
Below is a React function component which makes use of both the useSelector()
and the useDispatch()
hooks, without the need of the connect()
method. It is saved as selectAndDispatch.js
.
// selectAndDispatch.js
import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { fetchDogImage } from './redux/actions/dog';
import { fetchQuote } from './redux/actions/quote';
const App = () => {
const dogData = useSelector(state => state.dog);
const quoteData = useSelector(state => state.quote);
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchDogImage());
dispatch(fetchQuote());
console.log('quoteData', quoteData);
}, []);
return (
<div>
<img src={dogData.url} alt='dog'/>
<p>{quoteData.quote}</p>
<p>- {quoteData.role}</p>
</div>
);
}
export default App;
The function component selectAndDispatch.js
is invoked inside the index.js
file in the root directory and is wrapped by the <Provider/>
component to which is passed the Redux store as props.
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store';
import SelectAndDispatch from './selectAndDispatch';
ReactDOM.render(
<Provider store={store}>
<SelectAndDispatch/>
</Provider>
document.getElementById('root')
);
The component is rendered as follows:

We have made use of the useSelector()
and the useDispatch()
hooks, without the use of connect()
and the associated mapStateToProps()
and mapDispatchToProps()
functions.