React 状态管理

354 阅读4分钟

为什么react需要状态管理

React 只是 DOM 的一个抽象层,并不是 Web 应用的完整解决方案。在构建大型应用时往往需要考虑组件之间的通讯以及更好的代码结构;

Flux

2014年 Facebook 提出了 Flux 架构;

核心思想就是使用单向的数据流去处理数据。有以下基本概念: 

View; 视图层, 指用户能看到的部分; 

Store: 数据层, 存放应用和数据的方法; 

action: 故名思意,指动作, 即数据改变的消息对象;

Dispatcher: 派发器,接收 Actions,派发给store;

如下图所示,在flux中数据总是"单向流动",任何相邻的部分都不会发生数据的"双向流动"。

Redux

2015年,Redux 诞生,其本质就是flux架构在函数编程上的落地,本身和react毫无关系;

 有两个核心思想: 

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

  • 所有的状态,保存在一个对象里面(单一数据源)。

以及两个操作准则:

  • 保持状态只是只读 ;

  • 数据改变通过纯函数(reducer)完成;

核心概念如下:

Store

保存全局数据的地方,有且只有一个, 通过redux提供的createStore方法传入;

const store = createStore(reducer);

State

Store对象包含所有数据。如果想得到某个时点的数据,就要对 Store 生成快照。这种时点的数据集合,就叫做 State。 一个 State 对应一个 View。只要 State 相同,View 就相同。当前时刻的 State,可以通过store.getState()拿到; 

Action

 State 的变化,会导致 View 的变化。但是,用户接触不到 State,只能接触到 View。 action 是 view 和state沟通的桥梁; 数据结构是一个对象;store.dispatch(action)是 View 发出 Action 的唯一方法;

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

Action Creator

 故名思意action生成函数

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

 Reducer: 

 可以类比 数组的reduce方法 , 是一个纯函数,纯函数有以下特点:

1.相同的输入永远返回相同的输出

2.不修改函数的输入值

3.不依赖外部环境状态 无任何副作用 

reducer 的职责是接收当前 state 和一个 action 然后返回新的 state。 写法大概是这样的:

const initState = { count : 0 } 
function reducer(state = initialState, action) { .... return state; } 

store.subscribe() 

接受一个函数,当state变化的时候回调 ;

 react-redux 

react-redux 出现的目的就是方便人们去在react 使用redux, 提供了一些方便我们操作redux的语法糖; 

提出了UI组件与容器组件的概念:

Ui组件没有状态(state),只负责渲染,数据来源全部来自于props 容器组件,

容器组件:负责管理状态, 把状态传递给ui组件;

新提供的api

connect: 容器组件 = connect()(UI组件) 

但是有两个问题:

1. 数据如何传入到ui组件 2. ui组件触发的action如何传到状态组件;

解决方案:

 容器组件 = connect(stateToProps, dispatchToState)(UI组件) 

stateToProps :

mapStateToProps是一个函数。它的作用就是像它的名字那样,建立一个从(外部的)state对象到(UI 组件的)props对象的映射关系。

写法如下:

 const mapStateToProps = (state, ownprops) => {
     return { todos: getVisibleTodos(state.todos, state.visibilityFilter)}
} 

dispatchToState :

mapDispatchToProps connect函数的第二个参数,用来建立 UI 组件的参数到store.dispatch方法的映射。 也就是说,它定义了哪些用户的操作应该当作 Action,传给 Store。

它可以是一个函数,也可以是一个对象。 

 mapDispatchToProps: (dispatch,ownprops) => { 
        return { 
            onClick: 
                dispatch({ type: 'ON_CLICK', data: ownProps.filter })
          } 
     }

 如果mapDispatchToProps是一个对象,它的每个键名也是对应 UI 组件的同名参数, 返回的 Action 会由 Redux 自动发出:

const mapDispatchToProps = { 
    onClick: (filter) => { type: 'SET_VISIBILITY_FILTER', filter: filter };
}

组件:

组件 connect方法生成容器组件以后,需要让容器组件拿到state对象,才能生成 UI 组件的参数。 一种解决方法是将state对象作为参数,传入容器组件。但是,这样做比较麻烦,尤其是容器组件可能在很深的层级,一级级将state传下去就很麻烦。 React-Redux 提供Provider组件,可以让容器组件拿到state。

<Provider store={store}> <App /> </Provider> 

mirror

Mirror 是一个 react、redux 及 react-router 的封装。

让开发变得更加的简单和方便;

preview

初始化:

Mirror.defaults定义配置 -> 各个模块定义的Mirror.model 组织reducers、actions -> Mirror.render 生成store、包裹Provider、渲染DOM 调用actions: 

执行某个action:

相当于执行dispatch (store.dispatch({})) -> 对应Store中reducer执行,相当于用户定义的reducer执行 

 调用effects: 

同样执行某个action -> 但在reducers中没有这个action -> 中间件拦截之后,在effects中找到这个函数并执行