Redux 基本原理

47 阅读4分钟

Redux概述

1、是一个用于JavaScript状态容器,提供可以预测化的状态管理

2、可以让你构建一致化的应用,运行于不同的环境(客户端、服务器端、原生应用),并且易于测试

3、除了和React一起使用外,还支持其他界面库,而且它体积很小,只有2kb

Redux 三大核心

1、单一数据源:项目中的state改变不会影响到其他的state,整个应用的state被存储在一颗object tree中,并且这个object tree 只存在于唯一一个store中

2、State是只读的:唯一改变state的方法就是触发action,action是一个用于描述已发生事件的普通对象确保视图和网络请求都不能直接修改state,只能表达要修改的意图

3、使用纯函数来执行修改:为了描述action如何改变state tree,你需要去编写reducers, Reducers只是一些纯函数,它接收先前的state和action,并且返回新的state,可以复用、可以控制顺序,传入附加参数

Redux 的组成部分

state

1、就是我们传递的数据,可以分为三个大类

DomainDate: 从服务端获取的数据,比如获取用户的信息,商品的列表等

Ui State :决定当前ui展示的状态 ,弹框的显示和隐藏,受控组件等

App State :App级别的状态,比如:当前是否请求loading,当前路由信息等可能被多个组件使用到的状态

action 事件

action是把数据从应用传到store的载体,他是store数据的唯一来源,一般来说,我们可以通过store.dispatch()将action传递给store

store.dispatch

Component ================> Store

发送一个action

Action特点:

1、本质是一个javaScript的普通对象(可以通过一个函数返回一个对象,注意返回的对象中一定要有type)

2、对象内部必须要有一个type属性来表示要执行的动作

3、多数情况下,这个type会被定义成字符串常量

4、除type字段之外,action的结构随意进行定义

5、而我们项目中,更多的喜欢用action创建函数(就是创建action的地方)

6、只是描述了有事情要发生,并没有描述如何去更新state

reducers

Reducer本质就是一个函数(纯函数),他用来响应发送过来的actions,然后经过处理,把state发送给Store

注意:在Reducer函数中,必需要return返回值,这样Store才能接收到数据,函数会接收两个参数,第一个参数是初始化state,第二个参数是action

store.dispatch

Component ========> Reducer ========> Store

发送一个action

store

将action和reducer联系在一起的对象

主要职责:

1、维持应用的state

2、提供getState() 方法获取state

3、提供dispatch()方法发送action

4、通过subscribe()来注册监听

5、通过subscribe() 返回值来注销监听

构建store

import { createStore } from 'redux'

const store = createStore(传递reducer)

部分实现代码:

//  实现redux部分源码
/**
   preloadedState:初始时的 state
   enhancer:你可以选择指定它以使用第三方功能,如middleware、时间旅行、持久化来增强 store
 */
export const createStore = function createStore(reducer,preloadedState, enhancer) {

    // reducer 必须是一个函数
    if (typeof reducer !== 'function') throw new Error("Expected the root reducer to be a function")

    let state  // 存放公共状态
    let listeners = []  // 事件池

    // 获取公共状态
    const getState = function getState() {
        // 返回公共状态信息即可
        return state
    }

    // 向事件池中加入让组件更新的方法
    const subscribe = function subscribe(listener) {
        // 判断这个lister是不是函数
        if (typeof listener !== 'function') throw new TypeError('Expected the listener to be a function')

        // 把传入的更新组件的方法,存放在事件池中,【需要做去重处理】
        if (!listeners.includes(listener)) {
            listeners.push(listener)
        }

        // 返回一个从事件池中,移除方法的函数
        return function unsubscribe() {
            let index = listeners.indexOf(listener)
            listeners.splice(index, 1)
        }
    }

    // 派发任务通知Reducer执行
    const dispatch = function dispatch(action) {
        // 规则校验,action必须是一个对象,并且里面包含了type这个属性
        if (Object.prototype.toString.call(action) !== '[object Object]') {
            throw new TypeError("Action must be plain objects")
        }
        if (typeof action.type === 'undefined') throw new TypeError("Actions may not have an undefined 'type' property ")

        // 把Reducer执行,传递:公共状态、行为对象,还要接收执行的返回值,替换公共状态    
        state = reducer(state, action)

        // 当状态更改,我们还需要把事件池中的更新组件的方法执行
        listeners.forEach(listener => listener())

        return action
    }

    /* 
       replaceReducer:替换 store 当前用来计算 state 的 reducer。
       这是一个高级 API。只有在你需要实现代码分隔,而且需要立即加载一些 reducer 的时候才可能会用到它。
       在实现 Redux 热加载机制的时候也可能会用到。
    */
    // const replaceReducer = function replaceReducer(){
    // }

    // redux内部会默认进行一次dispatch派发,目的:给公共容器中的状态值赋初始值
    const randomString = () => Math.random().toString(36).substring(7).split('').join('.')
    dispatch({
        // type: Symbol() // 这个值要保证是唯一的,es6中可以直接使用Symbol数据类型
        type: randomString
    })

    // 返回创建的store对象
    return {
        dispatch,
        subscribe,
        getState,
        // replaceReducer
    }
}   

参考资料:

1、cn.redux.js.org/tutorials/e…

2、github.com/chyingp/red…