Redux 和 React-redux

redux 官網

先來看看 React 一些特點和沒有解決的問題:

  • 通信:組件之間如何通信?react 采用傳參,對于大應用,很不方便。
  • 數據流:數據如何和視圖串聯起來?路由和數據如何綁定?如何編寫異步邏輯?等等

為了解決這些問題引入 redux,前幾天看見一個博客,把 redux 的原理結合動圖把為什么使用 redux 講的特別透徹。

一定要看:Redux設計思想與使用場景

同時配上這篇:redux 設計思想

總結一下就是:

  • redux 的誕生是為了給 React 應用提供「可預測化的狀態管理」機制。

  • Redux 會將整個應用狀態(其實也就是數據)存儲到到一個地方,稱為 store。

  • 這個 store 里面保存一棵狀態樹(state tree)

  • 組件改變 state 的唯一方法是通過調用 store 的 dispatch 方法,觸發一個 action,這個action 被對應的 reducer 處理,于是 state 完成更新。

  • 組件可以派發 (dispatch) 行為 (action) 給 store,而不是直接通知其它組件

  • 其它組件可以通過訂閱 store 中的狀態 (state) 來刷新自己的視圖

一、初識 Redux

網站重要的開門注:

redux a predictable state container for JavaScript apps.
Redux是一個可預測狀態容器。

為了便于直觀理解,演示先不配合 React 使用,全部在一個文件 1.js 里面寫。使用 node 進行調試。

先安裝 redux。

npm install --save redux

實例代碼如下:

const redux = require("redux");

//①創建一個純函數reducers。
//這個函數接收兩個參數:一個 state、一個 action,并返回新的 state。
const reducers = (state = {a : 10},action)=>{
    if(action.type === "ADD"){
        return {
            a : state.a + 1
        }
    }else if(action.type === "UNADD"){
        return {
            a : state.a - 1
        }
    }
    return state;
}
// ②創建store
const store = redux.createStore(reducers);

// ③通過getState()方法可訪問state
console.log(store.getState().a);//10

// ④通過dispatch方法{type:"ADD"}進行一次加法運算
store.dispatch({type:"ADD"});
console.log(store.getState().a);//11

// ⑤通過dispatch方法{type:"UNADD"}進行一次減法運算
store.dispatch({type:"UNADD"});
console.log(store.getState().a);//10
  1. redux 依賴于一個純函數(reducer),它描述了 action 如何將 state 轉為新的 state,action 只說明了什么事情發生,但是不會描述 state 如何改變。絕對不能改變 state 對象,如果你要變,只能返回新的 state。什么是純函數?不改變傳入的參數的函數就是純函數。
  2. redux 通過 createStore 讓 store 和 reducers 產生聯系。
  3. 產生聯系的 store ,提供一個 getState() 方法來訪問純函數的 state,通過 dispatch({"type":...}) 來檢測命令。唯一能夠改變 state 的方法就是 dispatch 一個 action。store 就是統一管理 reducer 和 action 的,將所有的一切統一起來的。
  4. store 有三個主要的功能:
  • 持有 app 的 state
  • 允許通過 getState() 得到 state
  • 允許通過 dispatch 來改變 state

注意的是:可以有多個純函數,但只能有 1 個 store 。

  1. 我們知道 action 是 store 唯一的信息的來源且 action 需要被 dispatch() 函數派發,action 是純的、扁平的 JavaScript 對象。

如果需要多個純函數,則需要引入,combineReducers() 這個方法進行純函數合并。

const redux = require("redux");

//①創建一個純函數reducers。
const reducers = (state = {a : 10},action)=>{
    if(action.type === "ADD"){
        return {
            a : state.a + 1
        }
    };
    return state;
}
//⑥創建另一個純函數reducers2。
const reducers2 = (state = {a : 100},action)=>{
    if(action.type === "LOAD"){
        return {
            a : action.palyload
        }
    }
    return state;
}
// ⑦多個需求只能拆分純函數reducer,通過combineReducers合并成一個
const reducer = redux.combineReducers({
    reducers,
    reducers2
})
// ②創建store
const store = redux.createStore(reducer);

// ③通過getState()方法可訪問state的加命名空間
console.log(store.getState().reducers.a);//10

// 但是通過dispatch卻不用添加命名空間
store.dispatch({type:"ADD"});
console.log(store.getState().reducers.a);//11
//<============華麗的分割線===========>

// ③通過getState()方法可訪問state的加命名空間
console.log(store.getState().reducers2.a);//100

// action可通過playload攜帶負載參數
store.dispatch({type:"LOAD",palyload:"我是攜帶的負載!"});
console.log(store.getState().reducers2.a);//我是攜帶的負載

純函數里面的 action 就是由 type 屬性的組成的 JSON,但實際上不僅僅有 type 屬性,還可以有其他的屬性,所有其他的屬性都叫做載荷(payload)。

二、redux 結合 React

先安裝:react-redux粘合劑官網:https://react-redux.js.org/

npm install --save react-redux

梳理一下 redux 和 react-redux 提供各自提供的 API。

  • Redux 是可預測狀態容器(reducer、state、store、dispatch、action、applyMiddleware 等API)
  • react-redux 提供 Provider 和 connect 。

再看項目主要目錄結構:

┣? main.js
┣? index.html
┣? webpack.config.js
┣? package.json
┗? views
      ┣? app
            ┣? App.js
      ┗? store
            ┣? index.js
            ┗? counterStore.js

展示項目目錄代碼:

  • couterStore.js 放入純函數:
export default (state = {a : 10},action)=>{
    if(action.type === "ADD"){
        return {
            a : state.a + 1
        }
    }else if(action.type === "UNADD"){
        return {
            a : state.a - 1
        }
    };
    return state;
}

使用 redux 第一步必須是寫純函數。

  • index.js
import counterStore from "./counterStore.js";
import {combineReducers} from "redux";
export default combineReducers({
    counterStore
});

使用 combineReducers 進行純函數合并,變成一個統領文件

  • main.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./views/app/App.js";
import {createStore} from "redux";
import {Provider} from "react-redux";
import reducers from "./views/store";

const store = createStore(reducers);

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

引入 createStore 函數、引入r educers 統領文件、創建 store、可以測試使用store.getState().a輸出結果。Provider 可以讓 store 照耀在 APP 里面所有的組件上,做到天下無人不識君。Provider 的機理是使用的 context 上下文機理。

  • App.js
    connect 這里是個高階函數的用法,很明顯 connect 進行了柯粒化處理。這里叫做裝飾器。裝飾器兩個(mapStateToProps)(mapDispatchToProps),第一圓括號內部寫如何裝飾,映射全局 state 到組件的 props;第二個圓括號內部寫裝飾誰,將dispatch這個詞語映射到 props 上。
    寫法一:不使用裝飾器
import React,{Component} from "react";
import {connect} from "react-redux";

class App extends Component {
    constructor(){
        super()
    }
    render(){
        return(
            <div>
                <h1>{this.props.a}</h1>
                <button onClick = {this.props.add}>按我加一</button>
            </div>
        );
    }
}
export default connect(
    ({counterStore})=>({
        a : counterStore.a
    }),
    dispatch=>({
        add(){
            dispatch({type:"ADD"});
        }
    })
)(App);

寫法二:裝飾器寫法
react 不支持裝飾器寫法,首先安裝語法糖。

npm install --save @babel/plugin-proposal-decorators

參考 babel 官網 @babel/plugin-proposal-decorators · Babel
webpack.config.js 進行配置:

{
  "plugins": [
    ["@babel/plugin-proposal-decorators", { "legacy": true }]
  ]
}

配置完,重新開啟項目即可使用,改寫代碼:

import React,{Component} from "react";
import {connect} from "react-redux";
@connect(
    ({counterStore})=>({
        a : counterStore.a
    }),
    dispatch=>({
        dispatch
    })
)
export default class App extends Component {
    constructor(){
        super()
    }
    render(){
        return(
            <div>
                <h1>{this.props.a}</h1>
                <button onClick = {()=>{this.props.dispatch({type:"ADD"})}}>按我加一</button>
            </div>
        );
    }
}

兩者實現的效果都是一樣的。打開http://127.0.0.1:8080/,查看效果:

三、bindActionCreators(基本不用)

Action Creator 就是一個創建 action 的函數,例如:() => ({“type” : “ADD”})。不要混淆 action 和 action creator 這兩個概念。Action 是一個信息的負載,而 action creator 是一個創建 action 的工廠。調用 action creator 只會生產 action,但不分發。bindActionCreators 這個 API 就是使用 Action Creator。

使用場景?所以是基本沒用。

惟一會使用到 bindActionCreators 的場景是當你需要把 action creator 往下傳到一個組件上,卻不想讓這個組件覺察到 Redux 的存在,而且不希望把 dispatch 或 Redux store 傳給它。

bindActionCreators(actionCreators, dispatch)
參數

  1. actionCreators (Function or Object): 一個 action creator,或者一個 value 是 action creator 的對象。

  2. dispatch (Function): 一個由 Store 實例提供的 dispatch 函數。

更改 App.js

import React,{Component} from "react";
import {connect} from "react-redux";
import * as actionCreators from "./actionCreators.js";
import {bindActionCreators} from "redux";
@connect(
    ({counterStore})=>({
        a : counterStore.a
    }),
    (dispatch) => ({
        actionCreators: bindActionCreators(actionCreators , dispatch)
    })
)
export default class App extends Component {
    constructor(){
        super()
    }
    render(){
        return(
            <div>
                <h1>{this.props.a}</h1>
                <button onClick = {this.props.actionCreators.add}>按我加一</button>
            </div>
        );
    }
}
新增的actionCreators文件
export const add = ()=>({type:"ADD"});

加法器仍然起作用。

四、安裝 redux-logger

redux-logger 是每次 dispatch 的記錄器。當我們啟用 logger 的時候每次 dispatch ,都會在控制臺輸出每次詳情。而我們只需要一裝一引一配
一裝 redux-logger

npm install --save redux-logger

在主入口文件 main.js 中進行 一引一配

import React from "react";
import ReactDOM from "react-dom";
import App from "./views/app/App.js";
import {createStore,applyMiddleware} from "redux";
import {Provider} from "react-redux";
import reducers from "./views/store";
import logger from "redux-logger";
const store = createStore(reducers,applyMiddleware(logger));

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

輸入網址:http://127.0.0.1:8080/ 查看控制臺效果。

五、redux 的 hooks

hooks 在 v7.1.0 中首次被添加。這有一篇很好的文章,來介紹新出的 hook API 。
【譯】React Redux API Hooks

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容