DEV Community

Yogesh Datir
Yogesh Datir

Posted on • Updated on

React-Redux boiler-plate

Steps to use redux state management:

  1. store.js
  2. reducers (rootReducer and others)
  3. wrap App.js with Provider
  4. add actions and types
  5. use redux in components with connect() method.

Detail Guide to create a React-Redux boiler-plate (with Redux-thunk as a middleware):

1. Install redux and necessary libraries.

npm i redux react-redux redux-thunk redux-devtools-extension

  • React Redux is the official React binding for Redux. It lets your React components read data from a Redux store, and dispatch actions to the store to update data.
  • Redux Thunk: With a plain basic Redux store, you can only do simple synchronous updates by dispatching an action. Middleware extends the store's abilities, and let you write async logic that interacts with the store.
  • Redux Devtools Extension: to enable easy debugging and time travel.

2. Create src/store.js.

   import { createStore, applyMiddleware } from 'redux';
   import { composeWithDevTools } from 'redux-devtools-extension';
   import thunk from 'redux-thunk';
   import rootReducer from './reducers';

   const initialState = {};

   const middleware = [thunk];

   const store = createStore(
    rootReducer,
    initialState,
    composeWithDevTools(applyMiddleware(...middleware)),
   );

   export default store;
Enter fullscreen mode Exit fullscreen mode

3. Create reducers/index.js.

   import { combineReducers } from 'redux';

   export default combineReducers({});
Enter fullscreen mode Exit fullscreen mode

4. Wrap all root component - App with Provider.

   import React from 'react';

   import { Provider } from 'react-redux';
   import store from '../store';

   function App() {
     return (
       <Provider store={store}>
         <>This is App Component</>
       </Provider>
     );
   }

   export default App;
Enter fullscreen mode Exit fullscreen mode

5. Create actions/types.js.

   export const FETCH_POSTS = 'FETCH_POSTS';
   export const NEW_POST = 'NEW_POST';
Enter fullscreen mode Exit fullscreen mode

6. Create actions/clientActions.js.

   import { FETCH_POSTS, NEW_POST } from './types';

   export const fetchPosts = () => dispatch => {
     fetch('https://jsonplaceholder.typicode.com/posts')
       .then(res => res.json())
       .then(posts =>
         dispatch({
           type: FETCH_POSTS,
           payload: posts
         })
       );
   };

   export const createPost = postData => dispatch => {
     fetch('https://jsonplaceholder.typicode.com/posts', {
       method: 'POST',
       headers: {
         'content-type': 'application/json'
       },
       body: JSON.stringify(postData)
     })
       .then(res => res.json())
       .then(post =>
         dispatch({
           type: NEW_POST,
           payload: post
         })
       );
   };
Enter fullscreen mode Exit fullscreen mode

7. Create an reducer ./reducers/clientReducer.js.

   import { FETCH_POSTS, NEW_POST } from '../actions/types';

   const initialState = {
     items: [],
     item: {}
   };

   export default function(state = initialState, action) {
     switch (action.type) {
       case FETCH_POSTS:
         return {
           ...state,
           items: action.payload
         };
       case NEW_POST:
         return {
           ...state,
           item: action.payload
         };
       default:
         return state;
     }
   }
Enter fullscreen mode Exit fullscreen mode

8. Add the reducer entry in the root reducer ./reducers/index.js.

   import { combineReducers } from 'redux';
   import clientReducer from './clientReducer';

   export default combineReducers({
     posts: clientReducer
   });
Enter fullscreen mode Exit fullscreen mode

9. Use redux in components.

src/components/Post.js

   import React, { Component } from 'react';
   import PropTypes from 'prop-types';
   import { connect } from 'react-redux';
   import { fetchPosts } from '../../actions/clientActions';

   class Posts extends Component {
     componentWillMount() {
       this.props.fetchPosts();
     }

     componentWillReceiveProps(nextProps) {
       if (nextProps.newPost) {
         this.props.posts.unshift(nextProps.newPost);
       }
     }

     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,
     newPost: PropTypes.object
   };

   const mapStateToProps = state => ({
     posts: state.posts.items,
     newPost: state.posts.item
   });

   export default connect(mapStateToProps, { fetchPosts })(Posts);
Enter fullscreen mode Exit fullscreen mode

src/components/PostForm.js

   import React, { Component } from 'react';
   import PropTypes from 'prop-types';
   import { connect } from 'react-redux';
   import { createPost } from '../../actions/clientActions';

   class PostForm extends Component {
     constructor(props) {
       super(props);
       this.state = {
         title: '',
         body: ''
       };

       this.onChange = this.onChange.bind(this);
       this.onSubmit = this.onSubmit.bind(this);
     }

     onChange(e) {
       this.setState({ [e.target.name]: e.target.value });
     }

     onSubmit(e) {
       e.preventDefault();

       const post = {
         title: this.state.title,
         body: this.state.body
       };

       this.props.createPost(post);
     }

     render() {
       return (
         <div>
           <h1>Add Post</h1>
           <form onSubmit={this.onSubmit}>
             <div>
               <label>Title: </label>
               <br />
               <input
                 type="text"
                 name="title"
                 onChange={this.onChange}
                 value={this.state.title}
               />
             </div>
             <br />
             <div>
               <label>Body: </label>
               <br />
               <textarea
                 name="body"
                 onChange={this.onChange}
                 value={this.state.body}
               />
             </div>
             <br />
             <button type="submit">Submit</button>
           </form>
         </div>
       );
     }
   }

   PostForm.propTypes = {
     createPost: PropTypes.func.isRequired
   };

   export default connect(null, { createPost })(PostForm);
Enter fullscreen mode Exit fullscreen mode

Update the App.js

   import React from 'react';

   import Posts from './posts/Posts';
   import PostForm from './posts/PostForm';

   import { Provider } from 'react-redux';
   import store from '../store';

   function App() {
     return (
       <Provider store={store}>
         <div>
             <PostForm />
             <hr />
             <Posts />
           </div>
       </Provider>
     );
   }

   export default App;
Enter fullscreen mode Exit fullscreen mode

If you want the code, you can find it here:

You can find me here:

See you around!

Top comments (0)