ReactRedux for Front End Notes

Posted by johnbest on Fri, 02 Aug 2019 04:00:42 +0200

1. Redux Global Perception

Redux is a JavaScript state management container that provides a state management container for predictable states.From Flux, Facebook launched the Redux Library in 2015.

Chinese website: http://www.redux.org.cn/

Official git: https://github.com/reduxjs/redux

 

First, you'll reference the redux.js package, which provides a Redux object that can call the Redux.createStore() method.

<body>
    <h1 id="info"></h1>
    <button id="btn1">plus</button>
    <button id="btn2">reduce</button>
    <button id="btn3">ride</button>
    <button id="btn4">except</button>

    <script type="text/javascript" src="redux.min.js"></script>
    <script type="text/javascript">
        //This is a reducer,In the form of (state, action) => state Pure function of.
        //Pure function: function inside, does not change the parameters passed in, only return New value.
        //Description action How to put state Transform to Next state. 
        const reducer = (state = {"v" : 10} , action)=>{
            if(action.type == "ADD"){
                return {"v" : state.v + 1};
            }else if(action.type == "MINUS"){
                return {"v" : state.v - 1};
            }else if(action.type == "CHENG2"){
                return {"v" : state.v * 2}
            }
             return state;
        }
        //Establish Redux store To store the state of the application.
        //store Translated to Warehouse, this is something that stores and manipulates data
        const store = Redux.createStore(reducer);

        //Create a view function, and store Show on view.
        const render = ()=>{
            //The getState() method of the store can get the data in the warehouse
            document.getElementById("info").innerHTML = store.getState().v;
        }
        render(); //call render function
        //To add store Register with the view, so when store When the data in the is changed, it can be called automatically render function
        store.subscribe(render);

        // All in Application state All stored in a single object tree store Medium.
        // The only change state The way is to trigger action,An object describing what happened.
        // For description action How to change state Tree, you need to write reducers. 
        document.getElementById("btn1").onclick = function(){
            // The only way to change the internal state is to dispatch an action, and type indicates the action to be done
            store.dispatch({"type":"ADD"})
        }
        document.getElementById("btn2").onclick = function(){
            store.dispatch({"type":"MINUS"})
        }
        document.getElementById("btn3").onclick = function(){
            store.dispatch({"type":"CHENG"})
        }
    </script>
</body>

Create a function called reducer in which a quantity called state is maintained and the initial value is {"v": 0}.

 

There are two things you must know about this function:

1) It is a pure function that does not change the {"v": 0} inside the function, does not change the state object, but returns a new state.

const reducer = (state = {"v" : 0} , action)=>{
    if(action.type == "ADD"){
        return {"v" : state.v + 1};
    }else if(action.type == "MINUS"){
        return {"v" : state.v - 1};
    }
    return state;
}

 

2) This function provides predictable functionality.

The state in reducer is like being locked in a safe.Any change to this state can only be made by dispatch with an action.In other words, only dispatch has an action to change the data in this safe.

In the reducer function, an if statement is used to indicate a list of possible changes to the state. Only changes listed in the floor will occur:

if(action.type==""){
    return New state
}else if(action.type ==""){
    return New state
}else if(action.type ==""){
    return New state
}
Sample Code

Create a store warehouse that requires a reducer when it is created, so you can think of a store as a reducer and a reducer as a store.

const store = Redux.createStore(reducer);

Reducr is a pure function, while store provides three methods:

store.subscribe() registered with view

store.getState() gets data

store.dispatch() Send action

 

Learn to combine redux with react so you don't have to register to the view.

Then create a monitor:

document.getElementById("btn1").onclick = function(){
     store.dispatch({"type":"ADD"})
}
document.getElementById("btn2").onclick = function(){
     store.dispatch({"type":"MINUS"})
}
document.getElementById("btn3").onclick = function(){
     store.dispatch({"type":"CHENG"})
}
Sample Code

Click the button and store wants to dispatch an action.An action is a JSON that must have a type attribute with a value of uppercase letters.This action has no meaning, such as {"type":"ADD"}, but reducer knows it and can make a difference!

 

Case 2, Add Load:

<body>
    <h1 id="info"></h1>
    <button id="btn1">plus</button>

    <input type="text" id="txt">
<button id="btn2">Plus input</button>

    <script type="text/javascript" src="redux.min.js"></script>
    <script type="text/javascript">
        const reducer = (state = {"v" : 10}, {type, data})=>{
            if(type == "ADD"){
            return {"v" : state.v + action.data}
          return {"v" : state.v + data}
            }
            return state;
        }
        const store = Redux.createStore(reducer);
        const render = ()=>{
            document.getElementById("info").innerHTML = store.getState().v;
        }
        render();
        store.subscribe(render);

    document.getElementById("btn1").onclick = function(){
        store.dispatch({ type: 'ADD', data:100});
    }

        document.getElementById("btn2").onclick = function(){
            var a = parseInt(document.getElementById("txt").value);
            //load payload. 
            store.dispatch({"type":"ADD" , data:a});
        }
    </script>
</body>

The only way to change the state dispatch an action

 

Case 3: Add Array

<body>
    <div id="box">
        <p><input type="text" id="name"></p>
        <p><input type="text" id="age"></p>
        <button id="btn">increase</button>
        <ul id="List">

        </ul>
    </div>

    <script type="text/javascript" src="redux.min.js"></script>
    <script type="text/javascript">
        //Initial data
        const initObj = {
            "arr" : [
                {"name" : "Xiao Ming" , "age" : 12},
                {"name" : "Little Red" , "age" : 13},
                {"name" : "Cockroach" , "age" : 14}
            ]
        };
        //reducer function
        const reducer = (state = initObj, {type , name , age}) => {
            if(type == "ADD_STUDENT"){
                //cannot push Change the original array passed in, so return the new array
                return {
                    "arr" : [
                        {name , age} ,
                        ...state.arr
                    ]
                }
            }
            return state;
        }
        //Establish store
        const store = Redux.createStore(reducer);
        //View Functions
        const render = function(){
            //empty ul
            document.getElementById("List").innerHTML = "";
            //Establish li
            for(var i = 0 ; i < store.getState().arr.length ; i++){
                var li = document.createElement("li");
            var storeArr = store.getState().arr[i]
                li.innerHTML = storeArr.name + storeArr.age+"year"
                document.getElementById("List").appendChild(li);
            }
        }
        render();//Run View Function
        store.subscribe(render);//Register to View
        
        document.getElementById("btn").onclick = function(){
            var name = document.getElementById("name").value;
            var age = document.getElementById("age").value;
            //Issue Action,This is the only thing that can change store Ways to
            store.dispatch({"type" : "ADD_STUDENT", name, age })
        }
    </script>
</body>

 

Case 4, Deep Exercise:

<body>
    <h1 id="info"></h1>
    <h1 id="info2"></h1>
    <button id="btn">+</button>

    <script type="text/javascript" src="redux.min.js"></script>
    <script type="text/javascript">
        var initObj = {
            "a" : {
                "b" : {
                    "c" : {
                        "v" : 10
                    }
                },
                "m" : 8
            }
        }
        const reducer = (state = initObj , action) => {
            if(action.type == "ADD"){
                return {
                    ...state, 
                    "a" : {
                        ...state.a ,
                        "b" : {
                            ...state.a.b,
                            "c" : {
                                ...state.a.b.c ,
                                "v" : state.a.b.c.v + 1
                            }
                        }
                    }
                }
            }
            return state;
        }
        const store = Redux.createStore(reducer);
        const render = ()=>{
            document.getElementById("info").innerHTML = store.getState().a.b.c.v;
            document.getElementById("info2").innerHTML = store.getState().a.m;
        }
        render();
        store.subscribe(render);

        document.getElementById("btn").onclick = function(){
            store.dispatch({"type" : "ADD"});
        }
    </script>
</body>

2. Redux and React for Integrated Development

Using the Redux Predictable State Container during React development, there are two new dependencies to load:

redux: provides functions such as createStore, combineReducers, bindActionCreators

react-redux: Only two things are provided, <Provider>component, connect() function.

 

Install two dependencies:

npm install --save redux react-redux

 

Create the reducers folder and index.js, which exposes a pure function:

reducers/index.js:

export default (state = { v : 10}, action) => {
    return state;
}

 

main.js entry file:

import React from "react";
import ReactDOM from "react-dom";
import {createStore} from "redux";
import App from "./App.js";
import reducer from "./reducers";  //reducer function

//Establish Redux store To store the state of the application.
const store = createStore(reducer);

ReactDOM.render(
    <App></App>,
    document.getElementById("app")
);

There are two questions:

How can components access data in the store?

Automatically update the view of a component when data in the store changes

 

react-redux solves both problems.

Create the <Provider>component in main.js, which provides a top-level container for context delivery of stores so that stores can "inject" into all components

react-redux provides the Provider component to get the container component to the state

Provider wraps one layer outside the root component so that all App subcomponents get the state by default.

The principle is the context property of the React component, which places the store object in the context

import React from "react";
import ReactDOM from "react-dom";
import {createStore} from "redux";
import {Provider} from "react-redux";
import App from "./App.js";
import reducer from "./reducers";

//Establish store Warehouse
const store = createStore(reducer);

ReactDOM.render(
    <Provider store={store}>
        <App></App>
    </Provider>,
    document.getElementById('app')
);

To get the global store value in a component, you need to use the connect function, which provides the role of connecting the React component to the Redux store.

connect([mapStateToProps], [mapDispatchToProps])

The first parameter of connect(): The first parameter of the function mapStateToProps is Redux's store, which automatically binds the store's data to the component as props.

The second parameter of connect(): mapDispatchToProps Its function is to bind action s to components as props

 

It is generally understood that using connect binds state and dispatch to React components, enabling them to access redux data.

You often see the following:

export default connect()(App)

App.js

import React from "react";
import {connect} from "react-redux";
class App extends React.Component {
    constructor() {
        super();
     
    }
    render(){
        return <div>
            <h1>{this.props.v}</h1>
        </div>
    }
}
export default connect(
//This function return The value of the object that will automatically become the component's props. 
    (state) => {
        return {
            v : state.v
        }
    }
)(App);

Once connect()(App); connect a component, and the component updates the view as if its props had changed when the global store sends changes.

 

Write two buttons in App.js to add 1 and subtract 1:

import React from "react";
import {connect} from "react-redux";
class App extends React.Component {
    constructor() {
        super();
    }
    render(){
        return <div>
            <h1>{this.props.v}</h1>
            <button onClick={()=>{this.props.add()}}>+</button>
            <button onClick={()=>{this.props.minus()}}>-</button>
        </div>
    }
}
export default connect(
    (state) => {
        return {
            v : state.v
        }
    },
    (dispatch) => {
        return {
            add(){
                dispatch({"type" : "ADD"});
            },
            minus(){
                dispatch({"type" : "MINUS"});
            }
        }
    }
)(App);

Reducrs/index.js provides predictable state

export default (state = {"v" : 10} , action) => {
    if(action.type == "ADD"){
        return { "v" : state.v + 1 };
    }else if(action.type == "MINUS"){
        return { "v" : state.v - 1 };
    }
    return state;
}

 

Small case of student management system:

reducers/index.js

const initObj = {
    "arr" : [
        {"id" : 1, "name" : "Xiao Ming" , "age" : 12},
        {"id" : 2, "name" : "Little Red" , "age" : 13},
        {"id" : 3, "name" : "Xiao Gang" , "age" : 14}  
    ]
}
export default (state = initObj, {type, age, name, id})=>{
    if(type == "ADD_STUDENT"){
        return {
            ...state , 
            "arr" : [
                ...state.arr ,
                {
                    "id" : state.arr.reduce((a,b)=>{
                        return b.id > a ? b.id : a;
                    },0) + 1,
                    name, 
                    age
                }
            ]
        }
    }else if(type == "DEL_STUDENT"){
        return {
            ...state,
            "arr" : state.arr.filter(item=>item.id != id)
        }
    }
    return state;
}

 

App.js

import React from "react";
import {connect} from "react-redux";
class App extends React.Component {
    constructor() {
        super();
    }
    //Increase Students
    add(){
        var name = this.refs.name.value;
        var age = this.refs.age.value;
        this.props.addStudent(name, age)
    }
    render(){
        return <div>
            <p><input type="text" ref="name"/></p>
            <p><input type="text" ref="age"/></p>
            <button onClick={()=>{this.add()}}>Increase Students</button>
            {
                this.props.arr.map((item,index)=>{
                    return <p key={item.id}>
                        {item.id} {item.name} {item.age}year
                        <button onClick={()=>{this.props.delStudent(item.id)}}>delete</button>
                    </p>
                })
            }
        </div>
    }
}
export default connect(
//(state) => {
    //    return { arr : state.arr }
    //},
//Simplified Writing
    ({arr})=>{
        return { arr }
    },
    (dispatch)=>{
        return {
            addStudent(name, age){
                dispatch({"type" : "ADD_STUDENT", name, age})
            },
            delStudent(id){
                dispatch({"type" : "DEL_STUDENT" , id})
            }
        }
    }
)(App);

Principle Analysis

The first reason connect succeeds is because of the Provider component:

Wrap a layer around the original application component to make the entire application a subcomponent of the Provider

Receives store s of Redux as props and passes them through context objects to connect on descendant components

 

What did connect do?

It really connects Redux to React, which is packaged on the outside of our container components. It receives the States and dispatch es from the store s provided by Provider, passes them to a constructor, returns an object, and passes them to our container components as attributes.

 

Summary:

connect()(App), the first () takes two parameters, mapStateToProps and mapDispatchToProps.

Both parameters are functions, the key name of the object returned by the first parameter function is automatically bound to props, and the key name of the object returned by the second parameter function is also bound to props.

The object of the first parameter return is the value obtained from the state

The object of the second parameter return is to change the value of the state

 

If you're interested, take a look at the API documentation for the connect function:

https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options

No matter how big the application is, there is only one store, which "shines" on all components just like the deity. By default, all components cannot get data from the store. connect which component gets data, and the largest App component does wrap all components, but it does not mean that the App component is connected to the next generationThe other components of the table are also joined.

 

3. Redux Programming-TodoList

http://www.todolist.cn/

Create reducers in reducers/index.js based on project scenarios:

const initObj = {
    "todos": [
       {"id" : 1, "title" : "Having dinner",  "done" : false},
       {"id" : 2, "title" : "Sleep",  "done" : false},
       {"id" : 3, "title" : "Bean Bean","done" : false}
    ]
}

export default (state = initObj, action) => {
    return state;
}

 

Create TodoHd.js, TodoBd.js, TodoFt.js components respectively:

import React from "react";
export default class TodoHd extends React.Component {
    constructor() {
        super();
    }

    render() {
        return <div>
            <h1>I am TodoHd assembly</h1>
        </div>
    }
}
Sample Code

 

 

 

 

App.js Introducing Components

import React from "react";
import {connect} from "react-redux";

import TodoHd from "./components/TodoHd.js";
import TodoBd from "./components/TodoBd.js";
import TodoFt from "./components/TodoFt.js";

class App extends React.Component {
    constructor() {
        super();
    }
    
    render() {
        return <div>
            <TodoHd></TodoHd>
            <TodoBd></TodoBd>
            <TodoFt></TodoFt>
        </div>
    }
}
export default connect()(App)  
import React from 'react';
import {connect} from "react-redux";
import TodoItem from "./TodoItem.js";
class TodoBd extends React.Component {
    constructor(props){
        super(props);
    }
    render() {
        return (
            <div>
            //{JSON.stringify(this.props.todos)}
                {
                    this.props.todos.map(item=>{
                    //return <div key={item.id}>{item.title}</div>
                        return <TodoItem key={item.id} item={item}></TodoItem>
                    })
                }
            </div>
        );
    }
}  
//connect The goal is to ask "days" to have data and to have a full day.
//"All-weather"is a figure of speech, that is, to ask store To Data
export default connect(
    (state)=>{
        return {
            todos : state.todos
        }
    }
)(TodoBd);

 

TodoItem.js

import React from 'react';
export default class TodoItem extends React.Component {
    constructor(props) {
        super(props);
    }
    render() {
        return (
            <div className="todoItem">
                <input type="checkbox" checked={this.props.item.done}/>
                <span>{this.props.item.title}</span>
                <button>delete</button>
            </div>
        );
    }
}

 

TodoHd.js Add to-do

import React from 'react';
import {connect} from "react-redux";
class TodoHd extends React.Component {
    constructor(props) {
        super(props);
    }
    render() {
        return (
            <div>
                <input type="text" ref="titleTxt"/>
                <button onClick={()=>{
                    this.props.addTodo(this.refs.titleTxt.value);
                    this.refs.titleTxt.value = "";
                }}>Add to</button>
            </div>
        );
    }
}
//The purpose of this component is to change data, not data.
export default connect(
    null ,
    (dispatch)=>{
        return {
            addTodo(title){
                dispatch({"type":"ADDTODO", title})
            }
        }
    }
)(TodoHd);

 

Reducrs/index.js Write Predictable State

const initObj = {
    "todos" : [
        ...
    ],
}
export default (state = initObj, action)=>{
    if(action.type == "ADDTODO"){
        return {
            ...state, 
            "todos" : [
                ...state.todos, 
                {
                    "id" : state.todos.reduce((a,b)=>{
                        return b.id > a ? b.id : a;
                    },0) + 1,
                    "title" : action.title, 
                    "done" : false
                }
            ]
        }
    }
    return state;
}

TodoFt.js

import React from "react";
import {connect} from "react-redux";
class TodoFt extends React.Component {
    constructor() {
        super();
    }

    render() {
        return <div>
            //Current: Total {this.props.todos.length}Bar information--
            //Done {this.props.todos.filter(item => item.done).length}strip--
            //Not done {this.props.todos.filter(item => !item.done).length}strip
        </div>
    }
}

export default connect(
    (state)=>{
        return {
            todos:state.todos
        }
    }
)(TodoFt)
Sample Code

TodoItem cannot dispatch to store s independently because the component is days-long.

TodoBd help is needed because TodoBd is all day long.

 

This is a routine: all components that are map ped out of a loop statement are inconsistent, given by the data father, given by the ability to change store s.

The TodoBd.js component introduces the TodoItem.js component because the TodoItem component is map ped out, so the information is passed to each TodoItem, not to let TodoItem take the data all day by itself.

TodoBd.js

import React from 'react';
import {connect} from "react-redux";
import TodoItem from "./TodoItem.js";

class TodoBd extends React.Component {
    constructor(props) {
        super(props);
    }
    render() {
        //According to Global show Property to determine the current todos array
        if(this.props.show == "ALL"){
            var todos = this.props.todos;
        }else if(this.props.show == "ONLYDONE"){
            var todos = this.props.todos.filter(item=>item.done);
        }else if(this.props.show == "ONLYUNDONE"){
            var todos = this.props.todos.filter(item=>!item.done);
        }

        return (
            <div>
                {
                    todos.map(item=>{
                        return <TodoItem
                            key={item.id}
                            item={item}
                            delTodo={this.props.delTodo.bind(this)}
                            changeTodo={this.props.changeTodo.bind(this)}
                        ></TodoItem>
                    })
                }
            </div>
        );
    }
}
export default connect(
    (state)=>{
        return {
            todos : state.todos ,
            show : state.show
        }
    },
    (dispatch)=>{
        return {
            delTodo(id){
                dispatch({"type" : "DELTODO", id});
            },
            changeTodo(id , k , v){
                dispatch({"type" : "CHANGETODO", id, k, v});
            }
        }
    }
)(TodoBd);

 

TodoItem.js

import React from 'react';
export default class TodoItem extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            "onEdit" : false
        }
    }
    render() {
     const {id, title, done} = this.props.item;
        return (
            <div>
                <input 
                    type="checkbox" checked={done}
                    onChange={(e)=>{
              this.props.changeTodo(id, "done", e.target.checked)
            }}
                />
                {
                    this.state.onEdit 
                    ?
                    <input 
                        type="text" 
                        defaultValue={title} 
                        onBlur={(e)=>{
                            this.props.changeTodo(id,"title", e.target.value)
                            this.setState({"onEdit" : false})
                        }}
                    />
                    :
                    <span onDoubleClick={()=>{this.setState({"onEdit":true})}}>
            {title}
          </span>
                }

                <button onClick={()=>{this.props.delTodo(id)}}>delete</button>
            </div>
        );
    }
}

 

index.js

const initObj = {
    "todos" : [
        ...
    ],
    "show" : "ALL"       //ALL,ONLYDONE,ONLYUNDONE
}
export default (state = initObj, action) => {
    if(action.type == "ADDTODO"){
        ...
    }else if(action.type == "DELTODO"){
        return {
            ...state, 
            "todos" : state.todos.filter(item => item.id != action.id)
        }
    }else if(action.type == "CHANGETODO"){
        return {
            ...state, 
            "todos" : state.todos.map(item => {
                //If the item item traversed is different from the id item passed in aciton, return the original item
                if(item.id != action.id) return item;
                //Otherwise, return the modified item
                return {
                    ...item ,
                    [action.k] : action.v
                }
            })
        }
    }else if(action.type == "CHANGESHOW"){
        return {
            ...state, 
            "show" : action.show
        }
    }
    return state;
}

 

TodoFt.js

import React from 'react';
import {connect} from "react-redux";
import classnames from "classnames";

class TodoFt extends React.Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
            <div>
                <p>
                    //Currently a total of {this.props.todos.length}Bar information
//Finish {this.props.todos.filter(item=>item.done).length}strip
//Not done {this.props.todos.filter(item=>!item.done).length}strip
                </p>
                <p>
                    <button className={classnames({"cur":this.props.show == 'ALL'})}                                 
            onClick={()=>{this.props.changeShow('ALL')}}>View All             </button> <button className={classnames({"cur":this.props.show == 'ONLYDONE'})} onClick={()=>{this.props.changeShow('ONLYDONE')}}>See only done </button> <button className={classnames({"cur":this.props.show == 'ONLYUNDONE'})} onClick={()=>{this.props.changeShow('ONLYUNDONE')}}>See only what you haven't done </button> </p> </div> ); } } export default connect( (state) => { return { todos : state.todos , show : state.show } }, (dispatch) => { return { changeShow(show){ dispatch({"type" : "CHANGESHOW" , show}) } } } )(TodoFt);

4. logger Plugins

redux-logger is used to aid development.

npm install --save redux-logger

Change main.js:

import React from "react";
import ReactDOM from "react-dom";
import {createStore , applyMiddleware} from "redux";
import {Provider} from "react-redux";
import logger from "redux-logger";

import App from "./App.js";
//Introduce reducer
import reducer from "./reducers/index.js";

//Establish store
const store = createStore(reducer , applyMiddleware(logger));

ReactDOM.render(
    <Provider store={store}>
        <App></App>
    </Provider>
    ,
    document.getElementById("app-container")
);

You can also use the redux-devtools plug-in.

npm install --save-dev redux-devtools
npm install --save-dev redux-devtools-log-monitor
npm install --save-dev redux-devtools-dock-monitor
npm install --save-dev redux-devtools-chart-monitor

File:

https://github.com/reduxjs/redux-devtools

https://github.com/reduxjs/redux-devtools/blob/master/docs/Walkthrough.md

 

5. combineReducers and bindActionCreators

An application for a Web page may be multiple reducers, merged into one reducer, such as counter s and todo's reducers.

 

Redux provides a combineReducers method for splitting reducers by defining individual subreducer functions and then using this method, combining them into a large reducer.

Redux provides a bindActionCreators method for wrapping actions through dispatch, which can be created by bindActionCreators to call dispatch(action) "implicitly".

5.1 combineReducers

Reducrs/counter.js is a common pure function:

export default (state = {"v" : 10},action)=>{
    return state;
}

Data provided by reducers/todo.js:

const initObj = {
    "todos": [
        { "id": 1, "title": "Having dinner", "done": false },
        { "id": 2, "title": "Sleep", "done": false },
        { "id": 3, "title": "Bean Bean", "done": true }
    ] 
};

export default (state = initObj, action) => {
    return state
}
Sample Code

 

 

 

 

Reducrs/index.js Intelligent Merge using combineReducers provided by redux

import { combineReducers } from "redux";
import counter from "./counter.js";
import todos from "./todos.js";

//Exposure Consolidated reducer
export default combineReducers({
    counter,
    todos
})

 

main.js

import React from "react";
import ReactDOM from "react-dom";
import {createStore} from "redux";
import {Provider} from "react-redux";

import App from "./containers/App.js";
//Introduce reducer
import reducer from "./reducers";

// Establish Redux store To store the state of the application.
const store = createStore(reducer);

ReactDOM.render(
    <Provider store={store}>
        <App></App>
    </Provider>,
    document.getElementById("app")
);

 

containers/App.js component uses data

import React from 'react';
import {connect} from "react-redux";
class App extends React.Component {
    constructor(){
        super();
    }
    render() {
        return (
            <div>
                <h1>{this.props.v}</h1>
            </div>
        );
    }
}
export default connect(
    ({counter}) => ({
        v : counter.v
    })
)(App);

 

components/TodoList/index.js Component

import React from "react";
import { connect } from "react-redux";
class TodoList extends React.Component {
    constructor(){
        super();
    }
    render() {
        return (
            <div>
                <h1>I am TodoList</h1>
                {
                    this.props.todos.map(item=>{
                        return <p key={item.id}>{item.title}</p>
                    })
                }
            </div>
        )
    }
};
export default connect(
   ({todos: {todos}})=>{
        return {
            todos
        }
   }
)(TodoList)

 

containers/App.js introduces components:

import React from 'react';
import TodoList from "../components/todolist/index.js";
import Counter from "../components/counter/index.js";
 
export default class App extends React.Component {
    constructor(props) {
        super(props);
    }
    render() {
        return (
            <div>
                <Counter></Counter>
                <TodoList></TodoList>
            </div>
        );
    }
}

5.2 bindActionCreators

BidActionCreators binds action s and dispatch es and returns an object that is passed into the component as part of the props.

The main role of bindActionCreators is that stores can generally be passed down through the connext property of React through a Provider. The only use of bindActionCreators is that action creators need to be passed down to the child component, which does not receive stores and dispatch es passed on the parent component.

Official folder structure: https://github.com/reduxjs/redux/tree/master/examples/todomvc/src

 

actions/counterActions.js: Create a new actions folder to store type

// We will return One action The function of is called " action creator"
// So this file exposes several actions
export const add = () => ({ type: "ADD" })
export const minus = () => ({ type: "MINUS" })
export const cheng = () => ({ type: "CHENG" })
export const chu = () => ({ type: "CHU" })

 

counter/index.js counter component

import React from 'react';
import {bindActionCreators} from "redux";
import {connect} from "react-redux";
import * as counterActions from "../../actions/counterActions.js";

class Counter extends React.Component {
    constructor(props) {
        super(props);
    }
    render() {
        return (
            <div>
                <h1>Counter : {this.props.v}</h1>
                <button onClick={()=>{this.props.counterActions.add()}}>plus</button>
                <button onClick={()=>{this.props.counterActions.minus()}}>reduce</button>
                <button onClick={()=>{this.props.counterActions.cheng()}}>ride</button>
                <button onClick={()=>{this.props.counterActions.chu()}}>except</button>
            </div>
        );
    }
}
export default connect(
    ({counter}) => ({
        v : counter.v
    }),
    (dispatch) => ({
    //There dispatch,Equivalent to store In store.dispatch,For combination action
        counterActions : bindActionCreators(counterActions , dispatch)
    })
)(Counter);

 

app/reducers/counter.js:

import {ADD, MINUS, CHENG, CHU} from "../constants/COUNTER.js";

export default (state = {"v" : 0} , action) => {
    if(action.type == "ADD"){
        return {
            ...state , 
            "v" : state.v + 1
        }
    }else if(action.type == "MINUS"){
        return {
            ...state , 
            "v" : state.v - 1
        }
    }else if(action.type == "CHENG"){
        return {
            ...state , 
            "v" : state.v * 2
        }
    }else if(action.type == "CHU"){
        return {
            ...state , 
            "v" : state.v / 2
        }
    }
    return state;
}
Sample Code

 

 

 

 

todolist/index.js

import React from 'react';
import TodoHd from "./TodoHd.js";
import TodoBd from "./TodoBd.js";

export default class TodoList extends React.Component {
    constructor(props) {
        super(props);
    }
    render() {
        return (
              <div>
                  <h1>TodoList</h1>
                  <TodoHd></TodoHd>
                  <TodoBd></TodoBd>
              </div>
        );
    }
}

 

TodoHd.js

import React from 'react';
import {bindActionCreators} from "redux";
import {connect} from "react-redux";
import * as todoActions from "../../actions/todoActions.js";

class TodoHd extends React.Component {
    constructor(props) {
        super(props);
    }
    render() {
        return (
            <div>
                <input type="text" ref="titleTxt"/>
                <button onClick={()=>{this.props.todoActions.add(this.refs.titleTxt.value)}}
            >Add to
          </button>
            </div>
        );
    }
}
export default connect(
    null ,
    (dispatch) => ({
        todoActions : bindActionCreators(todoActions , dispatch)
    })
)(TodoHd);

 

TodoBd.js

import React from 'react';
import {bindActionCreators} from "redux";
import {connect} from "react-redux";
import * as todoActions from "../../actions/todoActions.js";

class TodoBd extends React.Component {
    constructor(props) {
        super(props);
    }
    render() {
        return (
            <div>
                {
                    this.props.todos.map(item=>{
                        return <p key={item.id}>
                            {item.title}
                            <button onClick={()=>{this.props.todoActions.del(item.id)}}>
                 //delete
                  </button>
                        </p>
                    })
                }
            </div>
        );
    }
}

export default connect(
    ({todo}) => ({
        todos : todo.todos
    }) ,
    (dispatch) => ({
        todoActions : bindActionCreators(todoActions , dispatch)
    })
)(TodoBd);

 

To prevent type naming conflicts for action s, store them separately in the const folder:

app\constants\COUNTER.js

export const ADD = "ADD_COUNTER";
export const MINUS = "MINUS_COUNTER";
export const CHENG = "CHENG_COUNTER";
export const CHU = "CHU_COUNTER";

app\constants\TODO.js

export const ADD = "ADD_TODO";
export const DEL = "DEL_TODO";

You can then introduce the above constants in the following files and replace the type string with uppercase constants

counterActions.js and todoActions.js in actions

l todo.js and counter.js in reducers

 

actions/TodoActions.js

import {ADD , DEL} from "../constants/TODO.js";
export const add = (title) => ({"type" : ADD, title});
export const del = (id) => ({"type" : DEL, id});

actions/counterActions.js:

import {ADD , MINUS , CHENG , CHU} from "../constants/COUNTER.js";
export const add = () => ({"type" : ADD});
export const minus = () => ({"type" : MINUS});
export const cheng = () => ({"type" : CHENG});
export const chu = (n) => ({"type" : CHU , n});

 

reducers/todo.js

import {ADD , DEL} from "../constants/TODO.js";
const initObj = {
    "todos" : [
        {"id" : 1 , "title" : "Having dinner" , "done" : false},
        {"id" : 2 , "title" : "Sleep" , "done" : false},
        {"id" : 3 , "title" : "Bean Bean" , "done" : false}
    ]
}
export default (state = initObj , action) => {
    if(action.type == ADD){
        return {
            ...state ,
            "todos" : [
                ...state.todos ,
                {
                    "id" : state.todos.reduce((a,b)=>{return b.id > a ? b.id : a},0) + 1,
                    "title": action.title,
                    "done" : action.done
                }
            ]
        }
    }else if(action.type == DEL){
        return {
            ...state ,
            "todos" : state.todos.filter(item => item.id != action.id)
        }
    }
    return state;
}

 

reducers/counter.js

import {ADD , MINUS , CHENG , CHU} from "../constants/COUNTER.js";

export default (state = {"v" : 0} , action) => {
    if(action.type == ADD){
        return {
            ...state , 
            "v" : state.v + 1
        }
    }else if(action.type == MINUS){
        return {
            ...state , 
            "v" : state.v - 1
        }
    }else if(action.type == CHENG){
        return {
            ...state , 
            "v" : state.v * 2
        }
    }else if(action.type == CHU){
        return {
            ...state , 
            "v" : state.v / action.n
        }
    }
    return state;
}

Topics: PHP React Javascript npm github