Updating Redux to 2021 (Functional vs Class Components)

Hello friends! As I am moving forward in the Full Stack Engineering job market, I have begun working code challenges for potential jobs. One I recently worked on was reviewing a pull requests for a React Native application using Redux and TypeScript. I did not have much practice with Redux before hand, and even less practice with TypeScript, but as I went through the code, I couldn’t help but notice how using class components really overly complicated the app. So I wanted to make a post that helps refactor React code to hopefully make it more readable and precise.

First let us start up with importing Redux to our index.js file and wrapping it in our provider.

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { Provider } from 'react-redux'
import store from './Redux/store'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more:
https://bit.ly/CRA-vitals
reportWebVitals();

Next we can set up our reducers by creating character.js file.

import { SET_CHARACTERS } from '../types'export default function characters(state=[], action){
switch(action.type){
case SET_CHARACTERS:
return action.characters
default:
return state
}
}

And then importing it into an index.js reducer to combine it with any future reducers we may make.

import { combineReducers } from 'redux'
import count from './count'
import characters from './characters'
export default combineReducers({
characters,
})

Next is setting up the Redux store. Below is my index.js.

import { createStore } from 'redux'
import rootReducer from '../reducers'
export default createStore(
rootReducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)

Finally I decided to export all my action types and import them into the character reducer as needed. Below is the types index.js

export const SET_CHARACTERS = 'SET_CHARACTERS'

If you’re curious about the file structure of my Redux files, you can reference the image below

Now that we have finished our Redux set up, we can look at our App.js.

So I want to show you how to transition React Redux code from class to functional components. First, let us see how we get our code running with class components.

import React, { Component } from 'react'
import './App.css';
import { connect } from 'react-redux'
class App extends Component { showCharacters = () => {
return this.props.characters.map(character => <h1> {character.name}</h1>)
}
componentDidMount(){
this.getCharacters()
}
getCharacters = () => {
fetch('https://rickandmortyapi.com/api/character/?page=7')
.then(response => response.json())
.then(({results}) => this.props.setCharacters(results))
}
render() {
return (
<div className="App">
{this.showCharacters()}
</div>
);
}
}
const mapStateToProps = (state) => {
return {
characters: state.characters
}
}
const mapDispatchToProps = (dispatch) => {
return {
setCharacters: (characters) => dispatch({type: "SET_CHARACTERS", characters})
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App)

Here we have a simple react app that grabs characters from the Rick and Morty API and stores them as state in the Redux store, then displays the names on the screen. As you can see, with class components, we can only grab functions and state using and . So let’s transition our App.js to a functional component.

import './App.css';
import { useEffect } from 'react'
import { connect } from 'react-redux'
function App(props) { function showCharacters(){
return props.characters.map(character => <h1>{character.name}</h1>)
}
useEffect(getCharacters, []) function getCharacters(){
fetch('https://rickandmortyapi.com/api/character/?page=7')
.then(response => response.json())
.then(({results}) => props.setCharacters(results))
}
return (
<div className="App">
{showCharacters()}
</div>
);
}
const mapStateToProps = (state) => {
return {
characters: state.characters
}
}
const mapDispatchToProps = (dispatch) => {
return {
setCharacters: (characters) => dispatch({type: "SET_CHARACTERS", characters})
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App);

As you can see, we were already able to clean up the code quite a bit, no longer to we need to use to call our functions or to access state. We are able to use to run our fetch on the page load. I believe this refactor is has already started to make out code simpler and easier to read. But can we go further? Let’s try using the Redux methods useDispatch and useSelector.

import './App.css';
import { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { SET_CHARACTERS } from './Redux/types'
export default function App() { const actionCreator = (characters) => ({
type: SET_CHARACTERS,
characters
})
const dispatch = useDispatch()
const characters = useSelector(state => state.characters)
function showCharacters(){
return characters.map(character => <h1>{character.name}</h1>)
}
useEffect(getCharacters, []) function getCharacters(){
fetch('https://rickandmortyapi.com/api/character/?page=7')
.then(response => response.json())
.then(({results}) => dispatch(actionCreator(results)))
}
return (
<div className="App">
{showCharacters()}
</div>
);
}

And now we have reduced our App.js code from 42 lines of code to 31 lines. We can use useDispatch and our actionCreator function to store characters in the Redux store, as well as using useSelector to grab those characters from the store. This allows our code to become exponentially cleaner as we start adding more state and actions. If you wish you can take this refactoring further by using using custom hooks and writing out fetch calls in their own file and importing them.

So I hope what you can take away from this blog post is the benefits of refactoring React and React Native codes using Redux and functional components.

Thank you for reading and I hope you have a good day!

Full Stack Software Developer