关于javascript:浅谈Redux-Action-Reducer-Store

4次阅读

共计 4190 个字符,预计需要花费 11 分钟才能阅读完成。

一、redux 是什么

简略来说,redux 就是 JavaScript 状态容器,提供可预测化的状态治理。也就是能够了解为state 的升级版,不再依赖于组件本身的管制,能够独立于组件而存在。

二、为什么须要应用 redux

从组件的角度看,如果你的利用有以下场景,能够思考应用 Redux

  • 某个组件的状态,须要共享
  • 某个组件状态须要在任何中央都能够拿到
  • 一个组件须要扭转全局状态
  • 一个组件须要扭转另一个组件的状态

产生下面状况是,如果不应用 Redux 或者其余状态管理工具,不依照肯定法则解决状态的读写,代码很快会变成一团乱麻。你须要一种机制,能够在同一个中央查问状态、改拜年状态、流传状态的变动。

三、Action 是什么

1.Action 概念

Action是把数据从利用传到 store 的有效载荷。它是 store 数据的惟一起源。一般来说你会通过 store.dispacth() 将 action 传到 store。

增加新 todo 工作的 action 是这样的:

const ADD_TODO = 'ADD_TODO'
{
  type: ADD_TODO,
  text: 'Build my first Redux app'
}

Action 实质上是 JavaScript 一般对象。咱们约定,action 内必须应用一个字符串类型的 type 字段来示意将要执行的动作。少数状况下,type 会被定义成字符串常量。当利用规模越来越大时,倡议应用独自的模块或文件来寄存 action。

2.Action 创立函数

Action 创立函数就是生成 action 的办法,”action” 和 ”action 创立函数 ” 这两个概念很容易混同,所以在应用的时候最好留神辨别。

在 Redux 中的 action 创立函数只是简略的返回一个 action:

function addTodo(text) {
  return {
    type: ADD_TODO,
    text
  }
}

四、Reducer 是什么

1.Reducer 概念

Reducers 指定了利用状态的变动如何响应 actions 并发送到 store 的,记住 actions 只是形容了_有事件产生了_这一事实,并没有形容利用如何更新 state。其实说白了,Reducer 就是一个纯函数,承受旧的 state 和 action,返回新的 state。

(previousState, action) => newState

2.Reducer 要留神的点

特地须要留神的一点是 reducer 必须是一个纯函数,也就是说永远不要 reducer 中做上面的操作:

  • 批改传入的参数
  • 执行有副作用的操作,如 API 申请和路由跳转
  • 调用非纯函数,如 Date.now()或 Math.random()

总之,就一句话,reducer 肯定要放弃污浊,只有传入的参数雷同,返回计算失去的下一个 state 就肯定雷同,没有非凡状况、没有副作用、没有 API 申请、没有变量批改,单纯执行计算。

3. 如何定义 Reducer

这是官网的一个简略的例子:

//reducer
function counter(state = 0, action) {switch (action.type) {
  case 'INCREMENT':
    return state + 1
  case 'DECREMENT':
    return state - 1
  default:
    return state
  }
}

因为 reducer 切实是会依据不同的 action 会返回不同的 state,所以它的款式十分的多种多样,所以在这里只是简略的介绍官网给出的一个非常简单的例子而已。

4.combineReducers(reducers)

(1)随着利用变得越来越简单,能够思考将 reducer 函数 拆分成多个独自的函数,拆分后的每个函数负责独立治理 state 的一部分。

(2)combineReducers 辅助函数的作用是,把一个由多个不同 reducer 函数作为 value 的 object,合并成一个最终的 reducer 函数,而后就能够对这个 reducer 调用 createStore 办法。

官网的实例:

rootReducer = combineReducers({potato: potatoReducer, tomato: tomatoReducer})
// rootReducer 将返回如下的 state 对象
{
  potato: {// ... potatoes, 和一些其余由 potatoReducer 治理的 state 对象 ...},
  tomato: {// ... tomatoes, 和一些其余由 tomatoReducer 治理的 state 对象,比如说 sauce 属性 ...}
}

合并后的 reducer 能够调用各个子 reducer,并将它们返回的后果合并成一个 state 对象。由 combineReducers() 返回的 state 对象,会将传入的每个 reducer 返回的 state 按其传递给 combineReducers() 时对应的 key 进行命名

(3)combineReducers 的返回值:(Function)一个调用 reducers 对象里所有 reducer 的 reducer,并且结构一个与 reducers 对象构造雷同的 state 对象。

(4)每个传入 combineReducers 的 reducer 都需满足以下规定:

  • 所有 未匹配到的 action,必须把它接管到的第一个参数也就是那个state 一成不变返回;
  • 永远不能返回 undefined。当过早 return 是非常容易犯这个谬误,为了防止错误扩散,遇到这种状况时 combineReducers 会抛出异样;
  • 如果 传入的 state 就是 undefined,肯定要返回对应的 reducer 的初始 state。依据上一条规定,初始 state 禁止应用 undefined。应用 ES6 的默认参数至语法来设置 state 很容易,但你也能够手动查看第一个参数是否为 undefined。

五、Store 是什么

1.Store 的概念

依照官网的说法,Store 就是把 action、reducer 分割在一起的对象,Store 有以下的职责:

  • 维持利用的 state;
  • 提供 getState() 办法获取 state;
  • 提供 dispatch(action) 办法更新 state;
  • 通过 subscribe(listener) 注册监听器;
  • 通过 subscribe(listener) 返回的函数登记监听器。

要留神的一点是 每一个 Redux 利用只有一个 store

2. 如何创立 store

创立 store 十分的简略,只须要咱们把之前应用 combineReducers()生成的 reducer 导入 即可,并传递 createStore()

import {createStore} from 'redux'
import todoApp from './reducers'
let store = createStore(todoApp)

createStore() 的 第二个参数是可选的 , 用于 设置 state 初始状态。这对开发同构利用时十分有用,服务器端 redux 利用的 state 构造能够与客户端保持一致, 那么客户端能够将从网络接管到的服务端 state 间接用于本地数据初始化。

let store = createStore(todoApp, window.STATE_FROM_SERVER)

六、简略实现一个 redux

在最近这段时间学习 redux 的过程中,看了好几遍官网的文档之后还是感觉本人对 redux 的理解停留在表象,只是晓得 action、reducer、store 别离是一个什么货色,怎么应用它们,然而却对其中的原理并不理解,于是我就去 GitHub 上将 redux 源码 clone 下来剖析了一下,筹备下一次写一篇对于 redux 的源码原理剖析的文章(等我把源码吃透了先)。那么当初就先应用 js 来实现一个简略的 redux 吧。

上面实现的 redux 次要有如下的几个性能:

  • 获取利用的 state
  • 发送 action
  • 监听 state 的变动

先来定义一个 store:

const store = {state: {}, // 全局惟一的 state,外部变量,通过 getState()获取
  listeners: [], // listeners,用来诸如视图更新的操作
  dispatch: () => {}, // 散发 action
  subscribe: () => {}, // 用来订阅 state 变动
  getState: () => {}, // 获取 state
}

手动实现一个 createStore:

const createStore = (reducer, initialState) => {
  // internal variables
  const store = {};
  store.state = initialState;
  store.listeners = [];
  
  // api-subscribe
  store.subscribe = (listener) => {store.listeners.push(listener);
  };
  // api-dispatch
  store.dispatch = (action) => {store.state = reducer(store.state, action);
    store.listeners.forEach(listener => listener());
  };
  
  // api-getState
  store.getState = () => store.state;
  
  return store;
};

接下来,咱们试一下它的成果:

// reducer
function counter(state = 0, action) {switch (action.type) {
  case 'INCREMENT':
    return state + 1
  case 'DECREMENT':
    return state - 1
  default:
    return state
  }
}

let store = createStore(counter)

store.subscribe(() =>
  console.log(store.getState())
)


store.dispatch({type: 'INCREMENT'})
// 1
store.dispatch({type: 'INCREMENT'})
// 2
store.dispatch({type: 'DECREMENT'})
// 1

发现曾经实现 redux 最根本的性能了。

总之,我感觉学习一个新的货色最好的方法就是去读一下它的源码,而后在本人理解的根底下来手动实现一个相似的货色,我感觉应该会对了解这个货色的原理很有帮忙。

正文完
 0