Today the react-redux team released version 7.1.0, which adds hooks to react-redux! Here’s a quick comparison of how it could change how you write components.
First, A Brief Overview of The New Toys
-
useSelector
: Pass in a function that takes the state as an argument and returns a value. Used to get a single value from state. Can act as a replacement for mapStateToProps. -
useDispatch
: returns a reference to the dispatch object. It can act as a replacement for mapDispatchToProps. -
useStore
: returns an instance of the store. Generally not recommended.
Example With Connect
An example component that stores a query and when a form is submitted to search. I wanted to keep the example simple, so use your imagination for the part where it fetches results.
import React from 'react'
import { connect } from 'react-redux'
const defaultSearchBar = ({ query, updateQuery, handleSearch }) => {
const handleSubmit = (e) => {
e.preventDefault()
handleSearch(query)
}
const handleChange = e => updateQuery(e.target.value)
return (
<form onSubmit={handleSubmit}>
<input
name="search"
value={query}
onChange={handleChange}
/>
</form>
)
}
const mapStateToProps = state => ({
query: state.query,
})
const mapDispatchToProps = dispatch => ({
updateQuery: newQuery => dispatch({ type: 'UPDATE_QUERY', payload: newQuery }),
handleSearch: newSearch => dispatch({ type: 'NEW_SEARCH', payload: newSearch }),
})
const connectedSearchBar = connect(
mapStateToProps,
mapDispatchToProps,
)(defaultSearchBar)
New Example With Hooks
In our new example, we have a few differences: We eliminate the connect function, mapStateToProps, and mapDispatchToProps entirely. This means our component no longer takes in props directly. Now, our form looks like this:
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
const hookedSearchBar = () => {
const dispatch = useDispatch()
const query = useSelector(state => state.query)
const handleSubmit = (e) => {
e.preventDefault()
dispatch({ type: 'NEW_SEARCH', payload: query })
}
const handleChange = e => dispatch({ type: 'UPDATE_QUERY', payload: e.target.value })
return (
<form onSubmit={handleSubmit}>
<input
name="search"
value={query}
onChange={handleChange}
/>
</form>
)
}
Creating Your Own Custom Hooks
If you have code that gets shared frequently between components, you can create a custom hook to keep all of that functionality together. Here’s an example of us isolating the redux-specific part of our form into its own hook:
useSearchQuery = () => {
const dispatch = useDispatch()
const query = useSelector(state => state.query)
const updateQuery = query => dispatch({ type: 'UPDATE_QUERY', payload: query })
const updateSearch = search => dispatch({ type: 'NEW_SEARCH', payload: search })
return { query, updateQuery, updateSearch }
}
Should You Make The Switch?
The ability to create redux hooks above is interesting, but I am also concerned that it could make code harder to test, as testing these components is already dead simple. I’m not sold either way, but I hope this comparison makes it easier for you to make informed decisions about your code base.
What's your take on the new react-redux hooks? I'd love to hear your input in the comments below!