305 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			305 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| 
								 | 
							
								---
							 | 
						||
| 
								 | 
							
								title: React Redux Basic Setup
							 | 
						||
| 
								 | 
							
								---
							 | 
						||
| 
								 | 
							
								## React Redux Basic Setup
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								In this guide it will be presented to the reader how to setup a simple React and Redux application.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								It's based on the principle that a [Node.js](https://nodejs.org/) application is already created and running with [Express](https://expressjs.com/) and [Webpack](https://webpack.github.io/).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Installation
							 | 
						||
| 
								 | 
							
								Assuming that all is setup and working correctly there are some packages that need to be added in order for Redux work with React.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Open a terminal inside the project folder that was created and issue the following command 
							 | 
						||
| 
								 | 
							
								```sh
							 | 
						||
| 
								 | 
							
								npm install --save react react react-dom react-redux react-router redux
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								What the command above does is install the packages locally and add a reference to the the package.json file under dependencies.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Also add to your browser of choice the following tool [Redux Dev Tools](https://github.com/zalmoxisus/redux-devtools-extension).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This will allow the developer to see the state of the application and it's changes and what actions are being triggered also.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Folder structure
							 | 
						||
| 
								 | 
							
								With all the dependencies installed it's strongly recomended to create a structure of folders inside your application similar to the one bellow for better code maintainability and organization.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								project_root
							 | 
						||
| 
								 | 
							
								│   index.js
							 | 
						||
| 
								 | 
							
								|
							 | 
						||
| 
								 | 
							
								└───client
							 | 
						||
| 
								 | 
							
								|   App.jsx
							 | 
						||
| 
								 | 
							
								|   NotFound.jsx
							 | 
						||
| 
								 | 
							
								|   
							 | 
						||
| 
								 | 
							
								└───common
							 | 
						||
| 
								 | 
							
								    │
							 | 
						||
| 
								 | 
							
								    └───actions
							 | 
						||
| 
								 | 
							
								    |   │  appActions.js
							 | 
						||
| 
								 | 
							
								    |      
							 | 
						||
| 
								 | 
							
								    └───constants
							 | 
						||
| 
								 | 
							
								    |   │  Actiontypes.js
							 | 
						||
| 
								 | 
							
								    |
							 | 
						||
| 
								 | 
							
								    └───reducers
							 | 
						||
| 
								 | 
							
								    |   │   appReducer.js
							 | 
						||
| 
								 | 
							
								    └───store
							 | 
						||
| 
								 | 
							
								        │   store.js
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								## Description of the application's components and how they interact with themselves and with redux
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Application entry point implementation
							 | 
						||
| 
								 | 
							
								  - /project_root/index.js 
							 | 
						||
| 
								 | 
							
								    - Is the entry point for the app it will contain the entry point for which store, and it will render the the App.jsx file.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Bellow is an example of the code that will be declared on the file
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```javascript
							 | 
						||
| 
								 | 
							
								import React from 'react';
							 | 
						||
| 
								 | 
							
								import {render} from 'react-dom';
							 | 
						||
| 
								 | 
							
								import {Router,Route,browserHistory} from 'react-router';
							 | 
						||
| 
								 | 
							
								import {Provider} from "react-redux";
							 | 
						||
| 
								 | 
							
								import store from "../common/store/store";
							 | 
						||
| 
								 | 
							
								import App from '../client/App';
							 | 
						||
| 
								 | 
							
								import NotFound from '../client/notFound';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								render(
							 | 
						||
| 
								 | 
							
								    <Provider store={store}>
							 | 
						||
| 
								 | 
							
								        <Router history={browserHistory}>
							 | 
						||
| 
								 | 
							
								            <Route path="/" component={App} />
							 | 
						||
| 
								 | 
							
								            <Route path="*" component={NotFound}/> 
							 | 
						||
| 
								 | 
							
								        </Router>
							 | 
						||
| 
								 | 
							
								    </Provider>,
							 | 
						||
| 
								 | 
							
								    document.getElementById('root')
							 | 
						||
| 
								 | 
							
								);
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								In this example the usual react imports are added to the file, but also some new ones, like the Router,Route,browserHistory.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This ones are responsible for handling routes if they are needed to the application.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								And also where the application store is added and allowed to work in the application.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Application Component Implementation
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The following file:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								- /client/App.jsx
							 | 
						||
| 
								 | 
							
								  - This file is the baseline application file and where react and redux will communicate between to each other.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```javascript
							 | 
						||
| 
								 | 
							
								import React, { Component } from 'react';
							 | 
						||
| 
								 | 
							
								import {connect} from 'react-redux';
							 | 
						||
| 
								 | 
							
								import PropTypes from 'prop-types';
							 | 
						||
| 
								 | 
							
								import {ActionA,ActionB,ActionC} from '../common/actions/appActions';
							 | 
						||
| 
								 | 
							
								class App extends Component{
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    // example of triggering the action inside a component
							 | 
						||
| 
								 | 
							
								    foo=()=>{
							 | 
						||
| 
								 | 
							
								        this.props.doStringMessage(`Hello World`);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    //default render function of the component
							 | 
						||
| 
								 | 
							
								    render(){
							 | 
						||
| 
								 | 
							
								        return(
							 | 
						||
| 
								 | 
							
								            // the base component
							 | 
						||
| 
								 | 
							
								        );
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * es6 fat arrow function to get information from the application state
							 | 
						||
| 
								 | 
							
								 * @param {*} state current state of the application
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								const mapStateToProps=state=>{
							 | 
						||
| 
								 | 
							
								    return {
							 | 
						||
| 
								 | 
							
								        ArrayValue:state.example.exapleArray,
							 | 
						||
| 
								 | 
							
								        StringMessage:state.example.exampleString,
							 | 
						||
| 
								 | 
							
								        bookApploggedIn:state.example.exampleBool,
							 | 
						||
| 
								 | 
							
								        ObjectValue:state.example.exampleObject
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * es6 fat arrow function to connect the actions declared in the action file to the the component as if they were common react props
							 | 
						||
| 
								 | 
							
								 * @param {*} dispatch function send to action file to be later processed in the reducer
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								const mapDispatchToProps=dispatch=>{
							 | 
						||
| 
								 | 
							
								    return {
							 | 
						||
| 
								 | 
							
								        doStringMessage:(value)=>{
							 | 
						||
| 
								 | 
							
								            dispatch(ActionA(value));
							 | 
						||
| 
								 | 
							
								        },
							 | 
						||
| 
								 | 
							
								        getArrayItems:()=>{
							 | 
						||
| 
								 | 
							
								            dispatch(ActionB());
							 | 
						||
| 
								 | 
							
								        },
							 | 
						||
| 
								 | 
							
								        doBooleanChange:(value)=>{
							 | 
						||
| 
								 | 
							
								            dispatch(ActionC(value));
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * this function connects the application component to be possible to interact with the store
							 | 
						||
| 
								 | 
							
								 * @param {*} mapStateToProps allows the retrieval of information from the state of the application
							 | 
						||
| 
								 | 
							
								 * @param {*} mapDispatchToProps allows the state to change via the actions defined inside
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								export default connect(mapStateToProps,mapDispatchToProps)(App);
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								The example above demonstrates how the base App component is setup and how it will interact with the redux architecture.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Also how to dispatch a defined action from the component which will be passed down to the store and make the changes on the application reducer.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Declaration of the Application Actions
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The following file:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								- /common/actions/appActions.js
							 | 
						||
| 
								 | 
							
								  - This file is where each of the actions defined are going to interact with the application state and the reducer.
							 | 
						||
| 
								 | 
							
								  - And also any external api call needed by the application should be made in here and then passed down to the reducer via the call of a action.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								 ```javascript
							 | 
						||
| 
								 | 
							
								 import {
							 | 
						||
| 
								 | 
							
								    APP_ACTION_A,
							 | 
						||
| 
								 | 
							
								    APP_ACTION_B,
							 | 
						||
| 
								 | 
							
								    APP_ACTION_C
							 | 
						||
| 
								 | 
							
								} from '../constants/Actiontypes';
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								* es6 constant to comunicate with reducer to perform a given action
							 | 
						||
| 
								 | 
							
								* @param {Object} value an object or any other type to be set in the reducer
							 | 
						||
| 
								 | 
							
								**/
							 | 
						||
| 
								 | 
							
								export const doActionA=value=>({
							 | 
						||
| 
								 | 
							
								    type:APP_ACTION_A,
							 | 
						||
| 
								 | 
							
								    value
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								* es6 constant to comunicate with reducer to perform a given action
							 | 
						||
| 
								 | 
							
								* @param{Object} an object or any other type to be set in the reducer
							 | 
						||
| 
								 | 
							
								**/
							 | 
						||
| 
								 | 
							
								export const doActionB=value=>({
							 | 
						||
| 
								 | 
							
								    type:APP_ACTION_B,
							 | 
						||
| 
								 | 
							
								    value
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								* es6 constant to comunicate with reducer to perform a given action
							 | 
						||
| 
								 | 
							
								* @param {Object} an object or any other type to be set in the reducer
							 | 
						||
| 
								 | 
							
								**/
							 | 
						||
| 
								 | 
							
								export const doActionC=value=>({
							 | 
						||
| 
								 | 
							
								    type:APP_ACTION_C,
							 | 
						||
| 
								 | 
							
								    value
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								* es6 constant that will be know to the component so that the interation be possible between the component and the state
							 | 
						||
| 
								 | 
							
								* @param {Object} value an object or any other type to be set in the reducer
							 | 
						||
| 
								 | 
							
								**/
							 | 
						||
| 
								 | 
							
								export const ActionA=value=>dispatch=>{
							 | 
						||
| 
								 | 
							
								    dispatch(doActionB(value));
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								* es6 constant that will be know to the component so that the interation be possible between the component and the state
							 | 
						||
| 
								 | 
							
								**/
							 | 
						||
| 
								 | 
							
								export const ActionB=()=>dispatch=>{
							 | 
						||
| 
								 | 
							
								    dispatch(doActionB(true));
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								 ```
							 | 
						||
| 
								 | 
							
								In the example code provided above, the item ```ActionB``` will be made available to the App.jsx component and when it's triggered by the component via a prop it will trigger the appropriate action inside this file and then to the reducer and change the state accordingly.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Action Types implementation
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The following file:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								- /common/constants/Actiontypes.js
							 | 
						||
| 
								 | 
							
								  - This file will contain the declaration of each of the actions types available to be used by the application.
							 | 
						||
| 
								 | 
							
								  - The declarations done here will have to made availale to the actions file in order for them do be handled in the application.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```javascript
							 | 
						||
| 
								 | 
							
								export const APP_ACTION_A='MAKE_A';
							 | 
						||
| 
								 | 
							
								export const APP_ACTION_B='MAKE_B';
							 | 
						||
| 
								 | 
							
								export const APP_ACTION_C='MAKE_C';
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								In the example above three actions types are declared and exported in order to be made available to be consumed.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Reducer implementation
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The following file:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								- /common/reducers/appReducer.js
							 | 
						||
| 
								 | 
							
								    - The reducer in essence is nothing more than a javascript pure function that will check if any of the conditions meets the action triggered and make the changes to the state, never mutating it.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```javascript
							 | 
						||
| 
								 | 
							
								 import {
							 | 
						||
| 
								 | 
							
								    APP_ACTION_A,
							 | 
						||
| 
								 | 
							
								    APP_ACTION_B,
							 | 
						||
| 
								 | 
							
								    APP_ACTION_C
							 | 
						||
| 
								 | 
							
								} from '../constants/Actiontypes';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								* es6 example of a declaration of the reducer 
							 | 
						||
| 
								 | 
							
								* @param {Object} state contains all the application's state properties needed
							 | 
						||
| 
								 | 
							
								* @param {action} action the action that will trigger the state's changes
							 | 
						||
| 
								 | 
							
								**/
							 | 
						||
| 
								 | 
							
								const ExampleAppReducer= (state = {
							 | 
						||
| 
								 | 
							
								    exampleBool:false, // boolean value
							 | 
						||
| 
								 | 
							
								    exampleString:'', // string value
							 | 
						||
| 
								 | 
							
								    exampleArray: [], // array value
							 | 
						||
| 
								 | 
							
								    onError:{
							 | 
						||
| 
								 | 
							
								        A:'',
							 | 
						||
| 
								 | 
							
								        B:'',
							 | 
						||
| 
								 | 
							
								        C:''
							 | 
						||
| 
								 | 
							
								    } // object with properties inside
							 | 
						||
| 
								 | 
							
								}, action) => {
							 | 
						||
| 
								 | 
							
								    //switch statement that will test every case and make the necessary changes, never mutating the state as it's being preserved always
							 | 
						||
| 
								 | 
							
								    switch(action.type){
							 | 
						||
| 
								 | 
							
								        case APP_ACTION_A:{
							 | 
						||
| 
								 | 
							
								            return {
							 | 
						||
| 
								 | 
							
								                ...state, // es6 epread operator to make a copy of the existing state object 
							 | 
						||
| 
								 | 
							
								                exampleBool:action.value // the state property changes accordingly to the value of the action triggered
							 | 
						||
| 
								 | 
							
								            };
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        case APP_ACTION_B:{
							 | 
						||
| 
								 | 
							
								            return {
							 | 
						||
| 
								 | 
							
								                ...state,
							 | 
						||
| 
								 | 
							
								                exampleString:action.value
							 | 
						||
| 
								 | 
							
								            };
							 | 
						||
| 
								 | 
							
								        },
							 | 
						||
| 
								 | 
							
								        case APP_ACTION_C:{
							 | 
						||
| 
								 | 
							
								            return {
							 | 
						||
| 
								 | 
							
								                ...state,
							 | 
						||
| 
								 | 
							
								                exampleArray:action.value
							 | 
						||
| 
								 | 
							
								            };
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        default:{
							 | 
						||
| 
								 | 
							
								            return state; // if any of the actions triggered is not defined here it will return the default state
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								export default ExampleAppReducer;
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								The code above ilustrates how a basic reducer is defined and makes changes to the state, via the testing of a certain condition.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Store implementation
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The file:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								- /common/store/store.js
							 | 
						||
| 
								 | 
							
								  - This file will contain the definition of the state tree of the app, in order to change the state inside, an actin needs to be dispatched to here.
							 | 
						||
| 
								 | 
							
								  - It's nothing more than an object with methods declared inside, most important the one to create the store
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```javascript
							 | 
						||
| 
								 | 
							
								import {createStore} from 'redux';
							 | 
						||
| 
								 | 
							
								import example from '../reducers/ExampleAppReducer';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export default createStore(
							 | 
						||
| 
								 | 
							
								    example
							 | 
						||
| 
								 | 
							
								);
							 | 
						||
| 
								 | 
							
								  ```
							 | 
						||
| 
								 | 
							
								The code above demonstrates how to define a simple application store. 
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This is the basic setup of a reducer, it can be expanded further and contain multiple stores for instance and also have some middleware added to it.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Further reading
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								As this guide is nothing more than a introduction to how react and redux work together and how to implement the architecture.
							 | 
						||
| 
								 | 
							
								It's strongly recomended for the reader of this guide to read the links bellow to be read and clone the repos and try them.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[Redux Docs](http://redux.js.org/)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[Redux Api](http://redux.js.org/docs/api/)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[Redux Examples](https://github.com/reactjs/redux/tree/master/examples)
							 |