基础前端React

Redux 和 React-redux

2019-09-25  本文已影响0人  CondorHero
redux 官网

先来看看 React 一些特点和没有解决的问题:

为了解决这些问题引入 redux,前几天看见一个博客,把 redux 的原理结合动图把为什么使用 redux 讲的特别透彻。

一定要看:Redux设计思想与使用场景

同时配上这篇:redux 设计思想

总结一下就是:

一、初识 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 有三个主要的功能:

注意的是:可以有多个纯函数,但只能有 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。

再看项目主要目录结构:

┣✈ main.js
┣✈ index.html
┣✈ webpack.config.js
┣✈ package.json
┗✈ views
      ┣✈ app
            ┣✈ App.js
      ┗✈ store
            ┣✈ index.js
            ┗✈ counterStore.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 第一步必须是写纯函数。

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

使用 combineReducers 进行纯函数合并,变成一个统领文件

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 上下文机理。

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/ 查看控制台效果。

上一篇下一篇

猜你喜欢

热点阅读