4/12/2021 5:00:44 PM

React and Redux can get pretty complicated and appears very complicated at the beginning. The following is an attempt to create a very simply introduction to adding Redux to your React app. We will create a class component and a functional component using the Redux store.


Add the following packages to package.json and run npm install.

"react-redux": "7.2.3", "redux-thunk": "2.3.0", "redux": "4.0.5",

Update index.js with the following imports and render.

//redux import { Provider } from "react-redux"; import store from "./redux/store"; ReactDOM.render( <React.StrictMode> <Provider store={store}> <App /> </Provider> </React.StrictMode>, document.getElementById('root') );

Update App.js with a component that will use the redux store

import Users01 from "./components/users01"; import Users02 from "./components/users02"; function App() { return ( <div className="App"> <h1>React Testing</h1> <Users01 /> <hr /> <Users02 /> </div> ); } export default App;

Create /components/users01.js (functional component)

import React, { useEffect } from 'react'; //redux //useSelector, useDispatch only works in functional components import { useSelector, useDispatch } from "react-redux"; import { users_list, users_add } from "../redux/actions/usersActions"; export default function Users01() { //this is the item in the store you are using (state.users.items) const users = useSelector(state => state.users.items); //this is used to call an action (populate the users in this case) const dispatch = useDispatch(); useEffect(() => { //on initial load, call the users list action dispatch(users_list()); }, []); return <> <button onClick={() => dispatch(users_add())}>Add User</button> <div className="users"> {users.map((item, index) => ( <h1 key={item.name}>{item.name}</h1> ))} </div></> }

Create /components/users02.js (class component)

import React, { Component } from 'react'; //redux import { connect } from "react-redux"; import { users_list, users_add } from "../redux/actions/usersActions"; class Users02 extends Component { async componentDidMount() { //this doesn't have to be called since it is being called in the functional component and the state is shared //this.props.dispatch(users_list()); } render() { //this is made possible be mapStateToProps const { users } = this.props; return <> <h1>Users: 02</h1> <button onClick={() => this.props.dispatch(users_add())}>Add User</button> <div className="users"> {users.map((item, index) => ( <h1 key={item.name}>{item.name}</h1> ))} </div></> } } //these are the state properties you want access to //these will get added to this.props const mapStateToProps = state => ({ users: state.users.items }); export default connect(mapStateToProps)(Users02);

Redux Store Functions


Create /redux/store.js

import { createStore, applyMiddleware } from "redux"; import thunk from "redux-thunk"; import rootReducer from "./reducers"; //webpack automatically checks index.js const middleware = [ thunk, ]; const store = createStore( rootReducer, applyMiddleware(...middleware) ); export default store;

Create /redux/actions/types.js

export const USERS_APPEND_ITEM = "USERS_APPEND_ITEM"; export const USERS_LIST_SUCCESS = "USERS_LIST_SUCCESS";

Create /redux/actions/userActions.js

import * as ActionTypes from "./types"; export function users_add() { let new_user = { name: Math.floor(Math.random() * 10000001) + 1, // returns a random integer from 1 to 10000000 }; return { type: ActionTypes.USERS_APPEND_ITEM, payload: new_user } } export function users_list() { //this async function is made possible by the thunk middleware //you will often need an async function if you are making an ajax request return async function (dispatch) { let items = []; //populate your items - normally would be an ajax call let number_of_users = 10; for (let x = 0; x < number_of_users; x++) { let user = { name: Math.floor(Math.random() * 10000001) + 1, // returns a random integer from 1 to 10000000 }; items.push(user); } //dispatch this action to redux reducers dispatch( { type: ActionTypes.USERS_LIST_SUCCESS, payload: items } ); } }

Create /redux/reducers/index.js

//combine the reducers import usersReducer from "./usersReducer"; import {combineReducers} from "redux"; const rootReducer = combineReducers({ users: usersReducer }); //if not using specific names // const rootReducer = combineReducers({ // usersReducer // }); export default rootReducer;

Create /redux/reducers/usersReducer.js

import * as ActionTypes from "../actions/types"; const initialState = { item: null, items: [], loading: false, error: null } const usersReducer = (state = initialState, action) => { switch (action.type) { case ActionTypes.USERS_LIST_SUCCESS: { var new_items = []; //merge with previous list??? if (state.items) { new_items = [...state.items, ...action.payload]; } else { new_items = action.payload; } return { ...state, loading: false, items: new_items }; } case ActionTypes.USERS_APPEND_ITEM: { var new_items = []; //merge with previous list if (state.items) { new_items = [...state.items, action.payload]; } else { new_items = [action.payload]; } return { ...state, items: new_items }; } default: return state; } } export default usersReducer;