前端筆記之React(六)ES6的Set和Map&immutable和Ramda和lodash&redux-thunk

1、ES6SetMap數據結構

MapSet都是ES6新的數據結構,都是新的內置構造函數,也就是說typeof的結果,多了兩個:css

Set 是不能重複的數組前端

Map 是能夠任何東西當作鍵的對象node

 

ES6 提供了新的數據結構 Set。它相似於數組,可是成員的值都是惟一的,沒有重複的值。react

let s = new Set();
s.add(1);
s.add(2);
s.add(3);
s.add(3);
s.add(3);
s.add(4);
s.add(5);
console.log(s)
示例代碼

 

 

 

集合中添加數據用add()方法,會自動過濾已經有的元素。c++

 

最快的數組去重方法:git

let s = new Set([1,2,3,3,3,4,5]);
console.log([...s])

let s = new Set([1,2,3,4,5]);
console.log(s.size)
console.log(s.has(5))
console.log(s.delete(5))
console.log(s)
示例代碼

 

集合的關注點是在元素裏面,而不關注順序,因此不提供s[0]來枚舉某項API,可是能夠轉爲數組[...s]github

 

JavaScript 的對象(Object),本質上是鍵值對的集合(Hash 結構),可是傳統上只能用字符串看成鍵。這給它的使用帶來了很大的限制。算法

爲了解決這個問題,ES6 提供了 Map 數據結構。它相似於對象,也是鍵值對的集合,可是「鍵」的範圍不限於字符串,各類類型的值(包括對象)均可以看成鍵。也就是說,Object 結構提供了「字符串—值」的對應,Map 結構提供了「值—值」的對應,是一種更完善的 Hash 結構實現。若是你須要「鍵值對」的數據結構,Map Object 更合適。express

let m = new Map();
const o = {a:1,b:2};
m.set("haha", 123);
m.set(o, 456)
m.set(888,789)
console.log(m)
console.log(m.get(o))
示例代碼

 

 

 

使用get()來獲得元素的值,key是區分類型的。npm


2、函數式編程庫

所謂的「函數式編程」指的是程序中的函數的是「純函數」,就表示一個函數不改變傳入的參數。

咱們以前大量使用...filtermap等等操做,略微麻煩,就有3個特別好用的函數式編程庫應運而生。

2.1 immutable.js

2.1.1概述

來自Facebook,是官方推薦的庫,immutable表示不可變。immutable老是返回新的對象,不會修改原對象。

 

immutable不是深拷貝對象,創造性的使用DIFF算法,有一個結構共享機制,它所作的是智能分析改變,讓改變後的元素能夠共享改變以前的一些結構。

Immutable 使用了 Structural Sharing(結構共享),即若是對象樹中一個節點發生變化,只修改這個節點和受它影響的父節點,其它節點則進行共享。

{
   a:{"x":1 , "y":2},
    b:{
        c:{"x":3, "y":4},
        d:{"x":5},
    }
}
{
   a:{"x":1 , "y":2},
    b:{
        c:{"x":8, "y":4},
        d:{"x":5},
    }
}

上面代碼中,顏色相同部分,仍是內存中同一個對象。


2.1.2基本講解

官方:http://facebook.github.io/immutable-js/docs/#/

安裝依賴:

npm install immutable --save

immutable提供了兩個數據類型:

ListMapimmutable本身封裝的一個類,List是不可變的數組,Map是不可變的對象。

 

fromJS() 將一個原生js數據類型轉換爲immutable類型的數據

toJS()   將一個immutable類型的數據轉換爲JS類型的數據。

List()Map() 用來建立新的ListMap對象(將原生JS對象和數組轉換到不可變的MapList

 

immutable思惟:

先用fromJS()List()Map()將原生JS的數組、對象、變爲ListMap對象

而後再操做,好比對數組的push操做

最後.toJS()immutable對象變爲原生JS的數組、對象

 

Nodejs環境中引包:

var immutable = require("immutable");
var List = immutable.List

const list1 = List(["白板","幺雞","三條","三萬"])
const list2 = list1.push("四條")
console.log(list1.toJS())
console.log(list2.toJS())

會發現push以後,原數組沒有改變,只返回了新數組。

上面案例是用List(原數組)將數組變爲List對象,也能夠用fromJS

 

var immutable = require("immutable");
var fromJS = immutable.fromJS

const list1 = fromJS(["白板","幺雞","三條","三萬"])
const list2 = list1.push("四條")
console.log(list1.toJS())
console.log(list2.toJS())

 

數組的頭尾操做,也不會改變原數組,都是返回新數組:

var immutable = require("immutable");
var fromJS = immutable.fromJS

const list1 = fromJS(["白板","幺雞","三條","三萬"])
const list2 = list1.push("四條")
const list3 = list1.pop()
const list4 = list1.unshift("東風")
const list5 = list1.shift()

console.log(list1.toJS())
console.log(list2.toJS())
console.log(list3.toJS())
console.log(list4.toJS())
console.log(list5.toJS())
示例代碼

 

更改set

set表示更改下標爲2的項爲「二筒」,注意不會真的改變原數組,而是返回新數組:

const list1 = fromJS(["白板","幺雞","三條","三萬"])
const list2 = list1.set(2,"二筒");

 

對象也有set

const obj1 = fromJS({"a" : 1, "b" : 2 ,"c" : 3})
const obj2 = obj1.set("b",888)

console.log(obj1.toJS())
console.log(obj2.toJS())

 

在數組中查找某一項,使用find(),尋找某一項下標用findIndex()

獲得Map對象的某一個鍵的值,要用get()方法

var immutable = require("immutable");
var fromJS = immutable.fromJS

const data = fromJS([
    {"id" : 1, "name" : "小明", "age" : 12},
    {"id" : 2, "name" : "小紅", "age" : 12},
    {"id" : 3, "name" : "小強", "age" : 13},
])

const item = data.find(item=>item.get("id") == 2);
console.log(item.toJS())

 

刪除用delete,刪除下標爲2的項

const list1 = fromJS([111,222,333,888,999]);
const list2 = list1.delete(2);
console.log(list1.toJS());
console.log(list2.toJS());

 

is()函數驗證是否相等

var {is , Map} = require("immutable");
let o1 = Map({a : 1, b : 2, c : 3});
let o2 = Map({a : 1, b : 2, c : 3});

console.log(o1 == o2);  //在內存中不相等
console.log(is(o1,o2)); //在immutable世界中是相等


2.1.3真實項目場景

真實項目場景 - 增長todo,用set設置,用get獲取

var immutable = require("immutable");
var fromJS = immutable.fromJS

const data = fromJS({
    "todos" : [
        {"id" : 1,"title" : "吃飯", "done" : false },
        {"id" : 2,"title" : "睡覺", "done" : false },
        {"id" : 3,"title" : "打豆豆", "done" : false },
    ],
    "show" : "ALL"
})

const newData = data.set( "todos",
    data.get("todos").push({"id" : 4,"title" : "打架", "done" : false})
)
console.log(newData.toJS())

 

真實項目場景 - 刪除id2todo,使用delete(2)

//刪除id爲2的項
const newdata = data.set(
"todos", 
data.get("todos").delete(data.get("todos").findIndex(item=>item.get("id")== 2)
));

console.log(newdata.toJS());

 

方法2

const newData = data.set(
    "todos",
    data.get("todos").filter(item=>item.get("id") != 2)
)

 

真實項目場景 - 改變id2的項title爲「吃雞」

方法1

var index = data.get("todos").findIndex(item=>item.get("id") == 2);
var item = data.get("todos").get(index)
const newData = data.set("todos",data.get("todos").set(index, item.set("title","吃雞")));

console.log(newData.toJS())

 

方法2

const newData = data.set("todos",data.get("todos").map(item=>{
    return item.get("id") == 2 ? item.set("title" , "吃雞") : item;
}))


2.1.4redux結合

改造TodoList項目:

只改變reducers中的文件夾的寫法,其它地方一概不改。

state的數據依然是原生JS的數組和對象,只不過在reducer函數運行中,瞬間變成爲immutableListMap了,可是出去的時候就toJS了,裏外裏,state仍是原生數組、對象。

import {fromJS , toJS} from "immutable";
const initObj = {
    "todos" : [
        {"id" : 1 , "title" : "吃飯" , "done" : false},
        {"id" : 2 , "title" : "睡覺" , "done" : true},
        {"id" : 3 , "title" : "打豆豆" , "done" : true}
    ],
    "show" : "ALL"         
}

export default (state = initObj, action) => {
    //下面的語句很重要,變爲immutable對象
    state = fromJS(state);

    if(action.type == "ADDTODO"){
         return state.set("todos", state.get("todos").push(
             {
                 "id" : state.get("todos").reduce((a,b)=>{
          return b.get("id") > a ? b.get("id") : a
          }, 0) + 1,
                 "title" : action.title,
                 "done" : false
             }
         )).toJS();
    }else if(action.type == "DELTODO"){
        return state.set(
"todos", 
state.get("todos").filter(item=>item.get("id") != action.id)
).toJS();
    }else if(action.type == "CHANGETODO"){
        return state.set(
"todos", 
state.get("todos").map(
item => item.get("id") == action.id ? item.set(action.k, action.v) : item
)
).toJS();
    }else if(action.type == "CHANGESHOW"){
        return state.set("show", action.show).toJS();
 } return state.toJS();
}

2.2 Ramda.js

純函數,也叫做「蘭姆達函數」,就是ramda這個詞。http://ramda.cn/

2.2.1函數柯里化基礎

函數柯里化(Currying),是把接受多個參數的函數變換成接受一個單一參數的函數,而且返回接受餘下的參數,並且返回結果的新函數。柯里化函數就是逐步傳參,逐步縮小函數的適用範圍,逐步求解的過程。

 

簡單的加法函數:

function add(x,y){
    return x + y;
}
add(2,3);//5

若是用函數柯里化接受兩個參數的函數變成單一參數,以下:

function add(x) {
    return function (y){
        return x + y
    }
}

console.log(add(2)(3))
示例代碼

 


 

2.2.2基本講解

npm install ramda --save

數組尾插一項:

var R = require("ramda");

var arr1 = ["紅中","白板","幺雞"];
var arr2 = R.append("一筒", arr1)
var arr3 = R.append("二筒")(arr1)

console.log(arr1)
console.log(arr2)
console.log(arr3)

被操做的元素放到最後一個參數。

 

 

數組頭插一項:

var R = require("ramda");

var arr1 = ["紅中","白板","幺雞"];
var arr4 = R.prepend("發財",arr1)

console.log(arr4)
示例代碼

 

 

 


2.2.3真實項目場景

改變對象的b屬性爲8

這裏使用了很是重要的方法R.lensProp()聚焦到某屬性,功能就是讓改變的值從原基礎上進行修改

var R = require("ramda");

const obj1 = {"a" : 1,"b" : 2,"c" : 3}
const obj2 = R.set(R.lensProp("b") , 8, obj1)
console.log(obj2)

 

刪除id2的項:

const state = {
    "todos": [
       {"id" : 1, "title" : "吃飯",  "done" : false},
       {"id" : 2, "title" : "睡覺",  "done" : false},
       {"id" : 3, "title" : "打豆豆","done" : false}
    ],
    "show":"ALL"
}

//刪除id爲2的項
const newstate = R.set(R.lensProp("todos"), R.filter(item=>item.id != 2, state.todos) , state);
console.log(newdata)

 

修改id2的項title爲吃雞

const newstate = R.set(R.lensProp("todos"),R.map(item => item.id == 2 ? 
R.set(R.lensProp("title"),"吃雞",item) : item , state.todos), state);

 

修改showONLYDONE

const newstate = R.set(R.lensProp("show") , "ONLYDONE", state);

基本上一條語句可以解決問題,再也不寫...了,而且相好比immutable,沒有MapList和對象、數組的轉換。


2.2.4redux結合

仍是用todolist舉例,在reducers/index.js中修改,下面標黃色的語句的R.__是佔位符:

var R = require("ramda");

const initObj = {
    "todos" : [
        {"id" : 1 , "title" : "吃飯" , "done" : false},
        {"id" : 2 , "title" : "睡覺" , "done" : true},
        {"id" : 3 , "title" : "打豆豆", "done" : true}
    ],
    "show" : "ALL"         
}

export default (state = initObj, action) => {
//R.__表示佔位符,下面調用setTodos時,就等於傳入了要更改爲爲的值
    const setTodos = R.set(R.lensProp("todos"), R.__ , state);
    const setShow  = R.set(R.lensProp("show") , R.__ , state);

    if(action.type == "ADDTODO"){
        return setTodos(R.append({
            "id" : state.todos.reduce((a,b) => b.id > a ? b.id : a, 0) + 1,
            "title" : action.title,
            "done" : false },state.todos));
    }else if(action.type == "DELTODO"){
        return setTodos(state.todos.filter(item=>item.id != action.id));
    }else if(action.type == "CHANGETODO"){
        return setTodos(state.todos.map(item=>item.id == action.id ? R.set(R.lensProp(action.k), action.v, item) : item))
    }else if(action.type == "CHANGESHOW"){
        return setShow(action.show);
    }
    return state;
}

2.3 lodash.js

2.3.1基本講解

實際上underscore.js已經在「函數庫工具」輸給了lodashlodash徹底能夠替代underscore

官網:https://lodash.com/

中文:https://www.lodashjs.com/

中文:http://www.css88.com/doc/lodash/

npm install --save lodash

 

underscore有的函數,lodash全有,好比數組去重和最大最小值:

var _ = require("lodash");

var arr1 = [3,3,3,3,4,4,4,4,5,5,5,5,3];
var arr2 = _.uniq(arr1);

console.log(arr1);
console.log(arr2);

console.log(_.max(arr1));
console.log(_.min(arr1));

 

lodash中有子包,叫作fpfpfunctional programing函數式編程的意思。

須要引入這個包

var fp = require("lodash/fp");

更改b屬性爲8

var fp = require("lodash/fp");

var obj1 = {"a" : 1 , "b" : 2 , "c" : 3};
var obj2 = fp.set("b" , 8 , obj1);

console.log(obj1);
console.log(obj2);
示例代碼

 

 

 

和ramda同樣,被操做對象寫最後一個參數。


2.3.2真實項目場景

刪除

var fp = require("lodash/fp");

const state = {
    "todos" : [
        {"id" : 1 , "title" : "吃1飯" , "done" : false},
        {"id" : 2 , "title" : "吃2飯" , "done" : false},
        {"id" : 3 , "title" : "吃3飯" , "done" : false}
    ],
    "show" : "ALL"
};

//刪除id爲2的項
const newstate = fp.set("todos", state.todos.filter(item => item.id != 2), state);

console.log(state);
console.log(newstate);

 

增長:

const newstate = fp.set("todos", fp.concat(
    state.todos,
    {
        "id" : state.todos.reduce((a,b) => b.id > a ? b.id : a, 0) + 1,
        "title": "吃雞",
        "done" : false
    }
) , state);

 

修改id2的項的title爲「吃雞」

const newstate = fp.set("todos",state.todos.map(item=>item.id == 2 ? fp.set("title", "吃雞", item) : item), state);

若是碰見比較難的場景,此時能夠用克隆方法,好比在第2項之間插入一項

const _todos = fp.clone(state.todos)

//更改克隆以後的數組
_todos.splice(2,0,{"id": 4,"title":"游泳","done":false})

//更改state
const newstate = fp.set("todos", _todos, state)
console.log(state)
console.log(newstate)
示例代碼
const car = {
    "cars" : {
        "a" : [
            {
                "name" : "奧迪" ,
                "series" : [
                    {
                        "name" : "A6",
                        "type" : "豪華轎車"
                    },
                    {
                        "name" : "A4",
                        "type" : "豪華轎車"
                    }
                ]
            },
            {
                "name" : "奧拓",
                "series" : [{"奧拓1號" : 2}]
            }
        ],
        "b" : [
            {"奔馳" : 1}
        ]
    }
}

//改變A6的車系爲普通轎車
var newstate = fp.cloneDeep(car);
newstate.cars.a[0].series[0].type = '普通轎車';

console.log(JSON.stringify(newstate))
示例代碼

2.3.3 redux結合

import fp from "lodash/fp"; 

const initObj = {
    "todos" : [
        {"id" : 1 , "title" : "吃飯" , "done" : false},
        {"id" : 2 , "title" : "睡覺" , "done" : true},
        {"id" : 3 , "title" : "打豆豆" , "done" : true}
    ],
    "show" : "ALL"         
}

export default (state = initObj, action) => {
    if(action.type == "ADDTODO"){
        return fp.set("todos" , fp.concat(state.todos , {
            "id" : state.todos.reduce((a,b) => b.id > a ? b.id : a , 0) + 1,
            "title" : action.title,
            "done" : false }), state);
    }else if(action.type == "DELTODO"){
        return fp.set("todos" , state.todos.filter(item => item.id != action.id) , state);
    }else if(action.type == "CHANGETODO"){
        return fp.set("todos", state.todos.map(item=>item.id == action.id ? fp.set(action.k,action.v,item) : item) , state);
    }else if(action.type == "CHANGESHOW"){
        return fp.set("show" , action.show , state);
    }
    return state;
}

3、異步

3.1搭建服務器

咱們將全部前端的東西都放入www文件夾中。

 

Node.jsapp.js實現數據接口:

var express = require("express");
var app = express();
app.use(express.static("www"))

app.get("/api",(req,res)=>{
    res.json({"result":8})
})
app.listen(3000);
示例代碼

3.2 redux-thunk解決異步

咱們如今有四個文件都沒有地方適合寫異步:componentsactionsconstantsreducer

因此React提供了react-thunk包,thunk是中間件,所謂的中間件就是在發出actionreducer進行改變的中間,要作的事。

https://www.npmjs.com/package/redux-thunk

 

安裝依賴:

npm install --save redux-thunk

main.js

import React from "react";
import ReactDOM from "react-dom";
import { createStore, applyMiddleware} from "redux";
import { Provider } from 'react-redux'
import thunk from 'redux-thunk' 
import reducers from "./reducers/index";
import logger from "redux-logger";
//引入父組件
import App from "./containers/App";

//建立Redux store 倉庫用來存放狀態
const store = createStore(reducers, applyMiddleware(logger, thunk))

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

 

components/counter/index.js組件,按鈕點擊以後作addServer

<button onClick={()=>{this.props.counterActions.addServer()}}>加服務器那麼多</button>

 

此時actions/counterActions.js文件中,就能夠寫異步函數了:

兩步:第一步請求服務器數據,第二步發出action。將服務器的返回結果,當作載荷發給reducer

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

//同步陣營,直接返回一個Action
export const add = () => ({"type" : ADD});
export const minus = () => ({"type" : MINUS});

//異步有兩個(),第一個()接受按鈕傳的參數,第二個()是系統給你的dispatch和getState
//export const addServer = (n)=> (dispatch, getState)=>{ 
//    alert(n) 
//    alert(dispatch)
//    alert(getState().counter.v)
//}

export const addServer = ()=> async (dispatch , getState) => {
    //發出Ajax請求,其實是fetch請求,fetch不是Ajax
    const {result} = await fetch("/api").then(data=>data.json());
    //發action,由於惟一能改變reducer的方法就是dispath一個action
    dispatch({"type" : ADDSERVER , result})
}

 

constants/COUNTER.js

export const ADDSERVER = "ADDSERVER_COUNTER";

reducers/counter.js

import {ADD , MINUS , ADDSERVER} from "../constants/COUNTER.js";
export default (state = {"v" : 0} , action) => {
    if(action.type == ADD){
        ...
    }else if(action.type == MINUS){
        ...
    }else if(action.type == ADDSERVER){
        return {
            "v" : state.v + action.result }
    } 
    return state;
}

 

若是使用fetch,要安裝babel插件:babel-plugin-transform-runtime

babelasync await翻譯成瀏覽器都不認識的語句了,因此要用插件解決,不讓babel翻譯:

const path = require('path');
module.exports = {
    entry : "./www/app/main",                             // 入口
    output: {
        path: path.resolve(__dirname, "www/dist"),         // 出口文件夾
        filename: "bundle.js"                             // 出口文件名
    },
    watch : true,                                         // 自動檢測變化,進行打包
    module: {                                            // 配置一些插件
        rules: [
            {
                test: /\.js$/,                            // 全部.js結尾的文件
                loader: "babel-loader",                // 都要使用babel-loader處理
                include: [path.resolve(__dirname, "www/app")],
                exclude: [path.resolve(__dirname, "node_modules")],
                options: {
                    presets: ["env" , "react"],
                    plugins: ["transform-object-rest-spread", "transform-runtime" ]
                }
            }
        ]
    }
}

如今講解重要知識,如何從服務器上請求默認數據,此時要經過:

 

結合Echarts.js使用

app.js服務端出數據接口:

var a = 0;
var b = 0;
var c = 0;
app.get("/api2" , (req,res)=>{
    res.json({
        "result": [
            { value: a, name: '清晰' },
            { value: b, name: '通常' },
            { value: c, name: '懵逼' }
        ]
    });
});

//投票接口
app.get("/toupiao/:zimu" , (req,res)=>{
    var zimu = req.params.zimu;
    if(zimu == "a") a++;
    if(zimu == "b") b++;
    if(zimu == "c") c++;
    
    res.json({
        "result": [
            { value: a, name: '清晰' },
            { value: b, name: '通常' },
            { value: c, name: '懵逼' }
        ]
    });
});

app.listen(3000);
示例代碼

containers/App.js

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

 

components/pie/index.js組件的構造函數中調用函數:

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

class Pie extends React.Component {
    constructor(props) {
        super(props);
        ///組件還沒上樹時,發異步請求數據
 props.pieActions.loadServer();
    }
//組件已經上樹,而後初始化echart結構
    componentDidMount(){
        this.pic = echarts.init(this.refs.pic);
    }
//React開發中沒有回調函數的,因此數據回來了,在組件將要更新的生命週期寫
    //組件將要更新,爲何會將要更新,由於reducer中的result變了!
    //爲何它變了,由於fetch回來了,從而發出dispatch,影響result了。
    componentWillUpdate(nextProps){
        //這是百度的圖表插件標準寫法,就是一個配置,最重要的是最後一項data,來自服務器
        var option = {
            tooltip: {
                trigger: 'item',
                formatter: "{a} <br/>{b}: {c} ({d}%)"
            },
            legend: {
                orient: 'vertical',
                x: 'left',
                data: ['清晰', '通常', '懵逼']
            },
            series: [
                {
                    name: '懵逼指數',
                    type: 'pie',
                    radius: ['50%', '70%'],
                    avoidLabelOverlap: false,
                    label: {
                        normal: {
                            show: false,
                            position: 'center'
                        },
                        emphasis: {
                            show: true,
                            textStyle: {
                                fontSize: '30',
                                fontWeight: 'bold'
                            }
                        }
                    },
                    labelLine: {
                        normal: {
                            show: false
                        }
                    },
                    //這裏呈遞數據
 data: nextProps.result
                }
            ]
        };
        //設置option,組件就能顯示圖表了
        this.pic.setOption(option);
  }

    render() {
        return (
              <div>
            <p>結果:{this.props.result}</p>
                <div ref="pic" style={{"width":"300px" ,"height":"300px"}}></div>
                <button onClick={()=>{this.props.pieActions.toupiao('a')}}>清晰</button>
                <button onClick={()=>{this.props.pieActions.toupiao('b')}}>通常</button>
                <button onClick={()=>{this.props.pieActions.toupiao('c')}}>懵逼</button>
              </div>
        );
    }
}

export default connect(
    ({pie})=>({
        result: pie.result
    }),
    (dipatch)=>({  pieActions: bindActionCreators(pieActions, dipatch) })
)(Pie);

 

actions/pieActions.js中寫異步請求數據

export const loadServer = () => async (dispatch , getState) => {
    //異步請求數據
    const {result} = await fetch("/api2").then(data=>data.json());
    //存儲到reducer
    dispatch({"type" : "LOADSERVER" , result}); }

export const toupiao = (zimu) => async (dispatch, getState) => {
    const { result } = await fetch("/toupiao/" + zimu).then(data => data.json()); dispatch({ "type": "LOADSERVER", result });
}

 

reducers/pie.js要處理action的工做

export default (state = {"result" : []} , action) => {
    if(action.type == "LOADSERVER"){
        return {"result" : action.result};
    }
    return state;
}

 

reducers/index.js

import {combineReducers} from "redux";
import counter from "./counter.js";
import pie from "./pie.js";
//暴露合併的reducer
export default combineReducers({
    counter ,
    pie
});

相關文章
相關標籤/搜索