Deep dive into react-redux with a thunk as a middleware to make the API calls on-load that makes your app faster.
When working with Redux, you will need three main things:
Actions: these are nothing but the objects that should have two properties, one describing the type of action, and one describing what should be changed in the app state.
Reducers: these are functions that implement the behavior of the actions. They change the state of the app, based on the action dispatched.
Store: it brings and connects the actions and reducers together, holding and changing the state for the whole app β there is only one store.
Redux lets your React components read data from a Redux store, and dispatch actions to the store to update data using reducers.
Let's deep dive into the redux:
- npm i redux redux-thunk redux-persist redux-logger
redux > actions > actions.js
export const GET_USERS = "GET_USERS";
redux > actions > taskAction.js
import {
GET_USERS,
} from "./actions";
export const GetUsers = () => {
console.log("GetUsers");
return dispatch => {
console.log("GetUsers dispatch");
axios.get(`https://reqres.in/api/users`)
.then(res => {
const persons = res.data;
dispatch({
type: GET_USERS,
users: response
});
})
};
};
export const AddUser = (params) => {
console.log("AddUser");
return dispatch => {
console.log("Add User dispatch");
axios.post(`https://reqres.in/api/users`, {params})
.then(response => {
console.log(response);
axios.get(`https://reqres.in/api/users`)
.then(res => {
console.log(res);
dispatch({
type: GET_USERS,
users: response
});
})
})
};
};
redux > reducers > index.js
import { combineReducers } from 'redux';
import TaskReducer from './taskReducer'; //add this line
const rootReducer = combineReducers({
task:TaskReducer //add taskreducer and name is task for future use.
});
export default rootReducer;
redux > reducers > taskReducer.js
import {
GET_USERS,
} from "../actions/actions";
const INITIAL_STATE = {
Users: [],
loading : false,
};
export default (state = INITIAL_STATE, action) => {
// console.log("task reducer" , action);
switch (action.type) {
case GET_USERS: {
return {
...state,
Users: action.users,
loading: false
};
}
default:
return state;
}
};
redux > store > store.js
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import reducers from '../reducers/index';
import { persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage'
const persistConfig = {
key: 'root',
storage: storage,
}
const middlewares = [thunk];
if (process.env.NODE_ENV === `development`) {
const { logger } = require(`redux-logger`);
middlewares.push(logger);
}
const persistedReducer = persistReducer(persistConfig, reducers)
export default () => {
let store = createStore(
persistedReducer,
applyMiddleware(...middlewares)
)
let persistor = persistStore(store)
return { store, persistor }
}
App.js should be look something like this,
import {
GetUsers
} from "./app/redux/actions/taskAction";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
}
}
componentDidMount() {
// making all API calls and store in the redux-store
this.props.GetUsers();
}
render() {
console.log("this.props.tasksss ", this.props.Loading);
return (
<div>
...
</div>
);
}
}
const mapStateToProps = state => ({
Loading: state.task.loading
});
const mapDispacthToProps = dispatch => {
return {
GetUsers: () => dispatch(GetUsers())
};
};
export default connect(
mapStateToProps,
mapDispacthToProps
)(App);
Apps main index.js should be look something like this,
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from "react-router-dom";
import './index.css';
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { Provider } from "react-redux";
import { PersistGate } from "redux-persist/lib/integration/react";
import configureStore from "./app/redux/store/store";
let { store, persistor } = configureStore();
ReactDOM.render(
<BrowserRouter>
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<App />
</PersistGate>
</Provider>,
</BrowserRouter>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
HomeComponents.js from where you get the Users from the redux store and add a new User using dispatch
import React from 'react';
import { connect } from "react-redux";
import { AddUser } from "../../redux/actions/taskAction";
class Home extends React.Component {
constructor(props) {
super(props);
}
// creating new user using Redux-Thunk
addNewUser = () => {
let data = {
"name": "muhammad awais",
"job": "developer"
}
this.props.submit(
data
);
}
render() {
// getting users from redux store
console.log("this.props.Users : ",this.props.Users);
return (
<div>
...
</div>
);
}
}
const mapStateToProps = state => ({
Users: state.task.Users
});
const mapDispacthToProps = dispatch => {
return {
submit: (data) => {
dispatch(AddUser(data))
}
};
};
// export default withStyles(styles)(ProductList);
export default connect(
mapStateToProps,
mapDispacthToProps
)(Home);
Thatβs all. for now. I will release some new articles in detail.
Top comments (16)
A few quick notes:
configureStore
APIcreateAsyncThunk
API that helps abstract the process of writing standard thunks that dispatch based on promisesconnect
usage with the "object shorthand" form ofmapDispatch
(and also it's even easier if you use our new React-Redux hooks API )I surely will do the next update to my repo with these recommended changes. great suggestions #mark.
I am here to get to know how to handle the errors, but bad luck you didn't cover up that part, I am hitting the API and got this object as an error in the http response->
For normal response, I check everytime if status === 1 then that means I am having positive response, but in case of status === 0 that means some error coming from the server side but i am unable to print this message bcz it directly goes to the catch block and there i am getting simple http default error.
Do you have any idea how can I show this error message ?
You have take that error from catch block and store in your component state and do render in the Error section, also you can use the Reusable toast service to show the error from catch block, so there are multiple solutions you have to manage in terms of your need. Thanks
You missing something the boilerplate is tested and verified after each and every commit. So yeah
recommend you give
redux-api-middleware
a look, it will change your redux/api game, and allow you to move fully to fetch api (i.e. ditch axios) :)For sure. I will get hands on with it π
can you please look up my comment and suggest me any way out of it? That would be really appreciable. :)
Great article and examples, thank you very much!
pleasure man. it's all about sharing knowledge with community as you learn and grow. #bambooVibes
Absolutely agree;)
getting axios is not defined error. plz suggest what is wrong
hey, we use axios to make http request from our react/angular app, so i think this error is raised because you haven't install axios npm. try this command on your terminal/cmd of your project destination
C:/projects/react-redux-app> npm install axios
If you've already installed axios and are still getting this error,
you probably forgot to import - import axios from 'axios'
I don't know if you've ever fixed this, but the Axios library has to be installed in order for this to work
Has this structure changed since the release of React-Router v6?