Redux lets react component states to be stored in a centralized manner. The idea is to be able to impact the state from one component and be able to reflect the change be applied to another one as they share the state through the store.
The biggest problem with bootstrapping redux with react is to keeping in mind the relations. I have found it easier to remember it in the following order.
Chronological Order:
1. Wrap main app return in Provider and pass store object to Provider as parameter. (Possible location: ./app.js)
2. Create store (Location: ./store.js)
2.1 While creating store you will need to pass your rootReducer (Location: ./reducers/index.js)
2.2 While creating rootReducer you need to combine other reducers (Example: ./reducers/postReducer.js)
2.3 While creating postReducer you need to bring in the action types. (Example: ./actions/type.js)
2.4 After creating type.js you need to create postActions.js to define actions allowed on Post component. (Example: ./actions/postActions.js)
2.5 Now that the Post actions are defined you need to connect it to the Post component. (Location: ./components/post.js)
To use redux in react you need to have redux, react-redux and redux-thunk installed. You can install them via node package manager by typing –
npm install redux react-redux redux-thunk
The first thing needed after installing the modules is to wrap the main app return call in <Provider> tag in your app.js or main app file. Make sure you import Provider from ‘react-redux’ in the app.js or your main app file. The provider requires that you give it a store object in it’s store parameter.
Step 1:
import React, {component} from 'react';
import {Provider} from 'react-redux';
import Posts from './components/posts';
import Store from './store';
class App extends React.Component{
render(){
return (
<Provider store={Store}>
<Posts/>
</Provider>
);
}
}
export default App;
You create the store object using redux’s createStore method. The method takes 3 parameters, they are 1) reducer 2) initial state 3) enhancer. You need to import createStore and applyMiddleware enhancer method from ‘redux‘ before you use them. Common approach is to save a store.js file at root and import it then pass the object as parameter. In the store.js file you should also import thunk from ‘redux-thunk‘ which is used for dispatching the action.
Step 2:
import {createStore, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';
const initialState = [];
const middleware = [thunk]
const Store = createStore(rootReducer, initialState, ...middleware);
export default Store;
This file is the rootReducer, located at ‘./reducers/index.js’. It will combine all separate reducers into single file. combineReducers() is used for combining the reducers. It must be imported.
Step 2.1:
import { combineReducers } from 'redux';
import postReducer from './postReducer';
export default combineReducers({
posts: postReducer
});
Step 2.2:
The following file is the ‘./reducers/postReducer.js’. It defines the initial state and the object to be returned based on the type of action.
import { FETCH_POSTS } from '../actions/types';
const initialState = {
items: [],
item: {}
};
export default function(state = initialState, action) {
switch (action.type) {
case FETCH_POSTS:
return {
...state,
items: action.payload
};
default:
return state;
}
}
Step 2.3:
Whole application can have many different action types. So, its best to store them all in a single file. For instance this file is stored at ‘./actions/types.js’;
export const FETCH_POSTS = 'FETCH_POSTS';
Step 2.4:
The following code is in ‘./actions/postActions.js’. This defines the fetchPosts() method. It needs to import action type values from ‘./actions/type.js’ so it can be dispatched as action type. The action type is a required element of the object here. Payload can be anything and not necessarily has to be payload.
import { FETCH_POSTS } from './types';
export const fetchPosts = () => dispatch => {
fetch('https://jsonplaceholder.typicode.com/posts')
.then(res => res.json())
.then(posts =>
dispatch({
type: FETCH_POSTS,
payload: posts
})
);
};
Step 2.5:
The following code is in ‘./components/Post.js’ here we connect the fetchPosts action and update the components properties from the store state values. If you notice this.props.fetchPosts() is called in componentWillMount() life-cycle method. The fetchPosts() method is injected as props when we connect the postAction with this component. The connection is set at the last line connect(mapStateToProps, { fetchPosts })(Posts);. Here the first parameter maps the state values to the component properties as per our requirement. The second parameter is taking the fetchPosts() method thats injected as property to this component.
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { fetchPosts } from '../actions/postActions';
class Posts extends Component {
componentWillMount() {
this.props.fetchPosts();
}
render() {
const postItems = this.props.posts.map(post => (
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.body}</p>
</div>
));
return (
<div>
<h1>Posts</h1>
{postItems}
</div>
);
}
}
Posts.propTypes = {
fetchPosts: PropTypes.func.isRequired,
posts: PropTypes.array.isRequired
};
const mapStateToProps = state => ({
posts: state.posts.items
});
export default connect(mapStateToProps, { fetchPosts })(Posts);
Reference:
– https://www.youtube.com/watch?v=93p3LxR9xfM
– https://github.com/bradtraversy/redux_crash_course
Leave a comment