# 一、redux

# 1】使用场景

React 只是 DOM 的一个抽象层,并不是 Web 应用的完整解决方案。有两个方面,它没涉及。

  • 代码结构
  • 组件之间通信(所有组件不限于有关系的组件)

对于大型的复杂应用来说,这两方面恰恰是最关键的。因此,只用 React 没法写大型应用。

为了解决这个问题,2014年 Facebook 提出了 Flux 架构的概念,引发了很多的实现。2015年,Redux 出现,将 Flux 与函数式编程结合一起,很短时间内就成为了最热门的前端架构。

"只有遇到 React 实在解决不了的问题,你才需要 Redux 。"

①简单说,如果你的UI层非常简单,没有很多互动,Redux 就是不必要的,用了反而增加复杂性。

  • 用户的使用方式非常简单
  • 用户之间没有协作
  • 不需要与服务器大量交互,也没有使用 WebSocket
  • 视图层(View)只从单一来源获取数据

②从组件角度看,如果你的应用有以下场景,可以考虑使用 Redux。

  • 某个组件的状态,需要共享
  • 某个状态需要在任何地方都可以拿到(全局使用
  • 一个组件需要改变全局状态
  • 一个组件需要改变另一个组件的状态

发生上面情况时,如果不使用 Redux 或者其他状态管理工具,不按照一定规律处理状态的读写,代码很快就会变成一团乱麻。你需要一种机制,可以在同一个地方查询状态、改变状态、传播状态的变化

# 2】设计思想

Redux 的设计思想很简单,就两句话。

(1)Web 应用是一个状态机,视图与状态是一一对应的。

(2)所有的状态,保存在一个对象里面。

请务必记住这两句话,下面就是详细解释。

Redux是一个可预测性(我们给一个固定的输入,那么必定可以得到一个相应的结果)的状态管理容器。

可以集中管理react中多个组件的状态。

# 三大原则:

1.单一数据源:整个react中的state状态都会被统一管理到store仓库中。(单一状态树)。store中的数据结构往往是个给应用使用的深度嵌套的对象。

2.state是只读的:我们不能够直接改变state状态而是要通过触发redux中的特定方法进行修改。(store.dispatch()View 发出 Action唯一方法。)

  • store 对象本身只有4个简单的方法作为 API:
    • store.dispatch(action)
    • store.subscribe(listener)
    • store.getState()
    • replaceReducer(nextReducer)
      • dispatch() 方法发送一个对象给 Redux ,这个对象就是 actionaction可以说是一个带着 type 属性和其他数据的载体(用来更新state),然后再提交到reducer更新state。 注意 type 属性的值,设计action对象时你要给它命名赋值。

3.使用纯函数来执行修改操作

  • 正如之前说的,Redux不允许应用直接修改state。它要求使用载action 来描述state的变化,通过发送actionstore来改变state为了描述action如何改变state tree,你需要编写reducers。(这一切都是在部署store,等待用户触发去action,然后再去reducer改变state

  • Reducer 只是一些纯函数,它接收两个参数:先前的stateaction,并返回新的 state

  • // Reducer Functionvar 
    someReducer = function(state, action) { ... return state;}
    
  • 在设计 Reducer 应当注意按照纯函数设计,纯函数有以下几个特征:

    • 不使用外界网络或数据库调用(是dispatch去调用)
    • 返回的值完全取决于其参数的值
    • 调用具有相同的参数集的一个纯函数始终返回相同的值
  • 总之,一个函数在程序执行的过程中只会根据输入参数给出运算结果,我们把这类函数称为“纯函数”。纯函数由于不依赖外部变量,使得给定函数输入其返回结果永远不变

    • 比如整数的加法函数,它接收两个整数值并返回一个整数值,对于给定的两个整数值,它的返回值永远是相同的整数值。

State 的变化,会导致 View 的变化。但是,用户接触不到 State,只能接触到 View。所以,State 的变化必须是 View 导致的。Action 就是 View 发出的通知,表示 State 应该要发生变化了

# 如果还不明白我们看一下这个最基本的使用过程:

首先,我们通过 Redux.createStore() 创建一个 store ,并把所有的 reducers 都作为其参数。 我们看下这个只有一个 reducer 的示例:

 
// 注意这儿使用 .push() 并不
// 是好的方法。只是这样比较易于展示这
// 个示例。我将会在下一节解释原因。
 
// Reducer 函数
var userReducer = function(state, action) {
  if (state === undefined) {
    state = [];
  }
  if (action.type === 'ADD_USER') {
    state.push(action.user);
  }
  return state;
}
 
// 建立一个 store 并把 reducer 传递进去
var store = Redux.createStore(userReducer);
 
// 发送我们的第一个 action 来改变 state
store.dispatch({
  type: 'ADD_USER',
  user: {name: 'Dan'}
});

简短的总结下这段代码发生了什么:

  • store 被建立了,并传递了一个 reducer。
  • reducer 规定应用程序的初始 state 是一个空数组。
  • 我们发送了一个 action,其 typeADD_USER,携带的数据是user: {name: 'Dan'},意为添加一个名为 Dan 的新用户
  • reducer 向 state 添加了新用户,并返回了更改后的 state,然后更新了 store

在这个示例中 reducer 实际上被调用了两次,一次是 store 被创建时,一次是使用 dispatch 发送 action 时。

当 store 被创建时,Redux 立即调用 reducer 并获取到 reducer 返回的初始 state。第一次调用 reducer 时 state 的值为 undefined,于是 reducer 返回了一个空的数组作为 store 的初始 state。

Reducer 在每次传递 action 时都会被调用。Action 只是描述了有事情发生了这一事实,reducer 指明应用如何更新 state。

示例中传递 action 时第二次调用了 Reducer,Reducer 通过 action 携带的 type 属性的值 ADD_USER 来判断如何处理 state。

可以把 Reducer 想想成一个漏斗,它接收先前的 state 和 action,输出新的 state 来更新 store:

# 3】基本使用

# ①npm 安装redux插件

npm install --save redux

# ②创建store.js

在redux文件夹下创建store.js文件:

  • 我们首先要使用createStore所以我们需要导入相关内容。
  • 调用createStore(fn)方法:createStore函数接受另一个函数作为参数,返回新生成的 Store 对象。(这个参数就是我们需要传入的是reducer,意思是把reducer加入到store仓库中。reducer回调函数是通过action来计算新的state)
import { createStore } from 'redux';
import { data } from './reducer';

export var store = createStore(data)

# ③创建reducer.js

Store 收到 Action 以后,必须给出一个新的 State,这样 View 才会发生变化。这种 State 的计算过程就叫做 Reducer。Reducer 是一个函数,它接受 Action 和当前 State 作为参数,返回一个新的 State。(使用reducer来通过action改变state)

在src下创建redux文件夹,在这个文件夹下新建reducer.js文件:

  • 所以下一步我们需要设置reducer函数,向里面传入两个固定参数,state和action
var obj = [{
    age: 18
}]

export function data(state = obj[0].age, action) {
    switch (action.type) {
        case 'add':
            return state + action.data;
        case 'del':
            return state - action.data
        default:
            return state;
    }
}

# ④创建action.js

State 的变化,会导致 View 的变化。但是,用户接触不到 State,只能接触到 View。所以,State 的变化必须是 View 导致的。Action 就是 View 发出的通知,表示 State 应该要发生变化了。Action 是一个对象。其中的type属性是必须的,表示 Action 的名称。其他属性可以自由设置,社区有一个规范可以参考。payload是携带的参数(这里是一个字符串)

const action = {
  type: 'ADD_TODO',
  payload: 'Learn Redux'
};

在src下创建redux文件夹,在这个文件夹下新建action.js文件:

  • 设置action对象,一个action行为必须含有一个type参数,其它属性可以自己定义。
    • 真正调用api获取数据的是dispatch,reducer是纯函数做的是传入相应action.type通过对应的写好的action.type对比做运算改变state的操作。
export function add(num) {
    return {
        type: 'add', data: num
    }
}

export function del(num) {
    return {
        type: 'del', data: num
    }
} 

# ⑤在组件中使用redux

  • 在view视图模板触发中需要使用store.dispatch(action)去分发action,然后才能去对应reducer中的找到对应的action.type计算出新的state。(注意在我们createStore(reducer)的时候就传入了reducer,也就是已经注册好了store,到时候只需要dispatch分发的时候传入相应的action,就可以找到reducer中对应的action方法去修改state
  • 这一切都是在reduxstore仓库中进行操作的,所以我们肯定还要导入store仓库才能使用。store仓库中的state使用store.getState()全部取出,然后把这个状态加入到组件当中
  • reducer中我们需要传入初始的state(或者旧状态)和用户行为action,然后返回的是通过不同的传入action行为改变后的state状态。
import React, { Component } from 'react'
import { store } from '../redux/store';
import * as action from '../redux/action';

export default class Home extends Component {
    state = {
        num: store.getState()
    }
    componentDidMount() {
        store.subscribe(() => {
            this.setState({ num: store.getState() })
        })
    }
    render() {
        return (
            <div>
                Home---{this.state.num}
                <button onClick={() => { store.dispatch(action.add(1)) }}>点我+1</button>
                <button onClick={() => { store.dispatch(action.del(1)) }}>点我-1</button>
            </div>
        )
    }
}

# 4】工作流程

Redux是将整个应用状态存储到一个地方上称为store,里面保存着一个状态树store tree,组件可以派发(dispatch)行为(action)给store,而不是直接通知其他组件,组件内部通过订阅store中的状态state来刷新自己的视图。

从组件入手分析:Redux 提供了一个叫 store 的统一仓储库,组件通过 dispatchstate 直接传入 store ,不用通过其他的组件。并且组件通过 subscribestore 获取到 state 的改变。store 就像一个管理 state 改变的“中间人”,组件之间的信息传递不必直接在彼此间进行,所有的 state 变化都通过 store 这唯一数据源。使用了 Redux ,所有的组件都可以从 store 中获取到所需的 state, 他们也能从 store 获取到 state 的改变。这比组件之间互相传递数据清晰明朗的多。

control层:store=createStore(reducer(state,action))

view层:store.dispatch(action.fun(..))

model层:state={xxx:store.getState()}

完全和vuex一模一样:reducer就是mutation。但是react需要组件订阅才能接收到state的更新。

vuex

Last Updated: 8/5/2020, 5:39:29 PM