Redux hooks have been around for quite some time now so why aren't you using them in your projects? Maybe you're just too attached to connect()
, mapStateToProps
and mapDispatchToProps
. Maybe you just haven't taken the time to research the Redux hooks and how to utilize them in your projects. Or maybe, you just find them to be a little bit confusing.
Don't worry because I too was just a little too comfortable with using the standard methods for Redux. But once I decided to jump in and actually implement the Redux hooks, I haven't looked back.
I'll help walk you through some examples of how you can replace mapStateToProps
and mapDispatchToProps
with the easy to use useSelector
and useDispatch
hooks.
Let's take a look:
// ../reducers/ui.js
import * as types from '../actions/types'
export const ui = (state=initialState, {type, payload}) => {
switch (type) {
case types.SET_EXERCISE_VISIBILTY:
console.log('action', payload)
return {
exerciseModal: payload
}
default:
return state
}
}
const initialState = {
exerciseModal: false
}
// ../reducers/exercises.js
import * as types from '../actions/types'
import { exercises as initialState } from '../initialState.js'
export const exercises = (state=initialState, {type, payload}) => {
switch (type) {
case types.FILTER_EXERCISES:
console.log(payload)
const newArray = initialState.filter(item => item.name.toLowerCase().includes(payload.toLowerCase()))
return [...newArray]
break;
default:
break;
}
return state
}
// ../reducers/index.js
import { ui } from './ui.js'
import { exercises } from './exercises.js'
import { combineReducers } from 'redux'
export default combineReducers({
exercises,
ui
})
// ../store/store.js
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import rootReducer from '../reducers'
export const store = createStore(rootReducer, applyMiddleware(thunk))
What I did here was created two separate reducer files. I imported them all into a single file, ../reducers/index.js
and utilized the Redux hook combineReducers
to combine them into a single root reducer.
In the ../store/store.js
file, I went ahead and created our Redux store with my root reducer and the thunk
middleware to allow me to perform my dispatches asynchronously.
Now let's create our actions:
// ../actions/types.js
export const SET_EXERCISE_VISIBILTY = 'SET_EXERCISE_VISIBILTY'
export const FILTER_EXERCISES = 'FILTER_EXERCISES'
// ../actions/actions.js
import * as types from './types.js'
export const setExerciseModalVisibilty = (visible) => dispatch => {
dispatch({type: types.SET_EXERCISE_VISIBILTY, payload: visible})
}
export const filterExercises = (filter) => dispatch => {
console.log(filter)
dispatch({type: types.FILTER_EXERCISES, payload: filter})
}
Here I created two separate files, one to store our actions and the other to store our types.
Now that we have those set up we can head on over to our index.js
file to set up our Provider
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.js';
import { Provider } from 'react-redux';
import { store } from './store/store.js'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
, document.getElementById('root'));
Alright, let's start using our reducers inside of our components now.
I'll show you how it would look utilizing mapStateToProps
, mapDispatchToProps
and connect
before refactoring it to utilize useSelector
and useDispatch
// using mapStateToProps and connect
import React from 'react'
import { TopBar } from './TopBar.js'
import { setExerciseModalVisibilty } from '../actions/actions'
import { connect } from 'react-redux'
const CurrentWorkout = (props) => {
return(
<>
<TopBar style={styles.topBar}>
<h2>
Current Workout
</h2>
</TopBar>
<div>
<p>
add some exercises
</p>
<button onClick={() => props.setExerciseVisibilityModal(!props.visible)}>
+
</button>
</div>
{props.visible && props.exercises.map(exercise => (<h3>{exercise.name}</h3>))}
</>
)
}
const mapStateToProps = ({ui, exercises}) => {
return {
visible: ui.exerciseModal,
exercises: exercises
}
}
const mapDispatchToProps = {
setExerciseModalVisibility
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(CurrentWorkout)
// using Redux hooks
import React from 'react'
import { TopBar } from './TopBar.js'
import { setExerciseModalVisibilty } from '../actions/actions'
import { useDispatch, useSelector } from 'react-redux'
const CurrentWorkout = (props) => {
const [visible, exercises] = useSelector(({ui, exercise}) => [ui.exerciseModal, exercises])
const dispatch = useDispatch()
return(
<>
<TopBar style={styles.topBar}>
<h2>
Current Workout
</h2>
</TopBar>
<div>
<p>
add some exercises
</p>
<button onClick={() => dispatch(setExerciseModalVisibilty(!visible))}>
+
</button>
</div>
{visible && exercises.map(exercise => (<h3>{exercise.name}</h3>))}
</>
)
}
export default CurrentWorkout
As you can see, by utilizing useSelector
we can return an array with our wanted state directly inside of our component.
Similarly, we can use useDispatch
to create a reference to our dispatch functions inside of our Redux store. We can then pass our action inside of that dispatch reference.
Next time, I'll show you how you can implement the Redux Toolkit into your projects.
For a deeper dive into Redux hooks, be sure to check out the official docs here
Top comments (0)