Redux学习

来源:互联网 发布:美国大学统计 知乎 编辑:程序博客网 时间:2024/06/16 06:52

一 、简介

Redux对于JavaScript应用而言是一个可预测状态的容器。换言之,它是一个应用数据流框架,而不是传统的像underscore.js或者AngularJs那样的库或者框架。Redux最主要是用作应用状态的管理。简言之,Redux用一个单独的常量状态树(对象)保存这一整个应用的状态,这个对象不能直接被改变。当一些数据变化了,一个新的对象就会被创建(使用actions和reducers)。

二、 优点

 1.始终有一个准确的数据源,就是store, 对于如何将actions以及应用的其他部分和当前的状态同步可以做到绝不混乱。 2.具备可预测结果的性质和严格的组织结构让代码更容易维护。 3.对代码应该如何组织更加严苛,这使代码更加一致,对团队协作更加容易。 4.编写可测试代码的首要准则就是编写可以仅做一件事并且独立的小函数。Redux的代码几乎全部都是这样的函数:短小、纯粹、分离。

三、设计思想

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

(1)Web 应用是一个状态机,视图与状态是一一对应的。(2)所有的状态,保存在一个对象里面。

四、基本概念

4.1、Store

Store 就是保存数据的地方,你可以把它看成一个容器。整个应用只能有一个 Store。
Redux 提供createStore这个函数,用来生成 Store。

import rootReducer from './reducers/index'import {createStore, applyMiddleware} from 'redux';// applyMiddlewares  它是 Redux 的原生方法,作用是将所有中间件组成一个数组,依次执行const store = createStore(  rootReducer,   //reducer函数  applyMiddleware(thunk) );

上面代码中,createStore函数接受另一个函数作为参数,返回新生成的 Store 对象。

4.2、State

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

import { createStore } from 'redux';const store = createStore(fn);const state = store.getState();

Redux 规定, 一个 State 对应一个 View。只要 State 相同,View 就相同。你知道 State,就知道 View 是什么样,反之亦然。

4.3、Action

State 的变化,会导致 View 的变化。但是,用户接触不到 State,只能接触到 View。所以,State 的变化必须是 View 导致的。Action 就是 View 发出的通知,表示 State 应该要发生变化了。
Action 是一个对象。其中的type属性是必须的,表示 Action 的名称。其他属性可以自由设置。

4.4、Reducer

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

4.5、store.dispatch()
store.dispatch()是 View 发出 Action 的唯一方法。

import { createStore } from 'redux';const store = createStore(fn);store.dispatch({  type: 'ADD_TODO',  payload: 'Learn Redux'});

store.dispatch接受一个 Action 对象作为参数,将它发送出去。

五、中间件

用户发出 Action,Reducer 函数算出新的 State,View 重新渲染。但是,一个关键问题没有解决:异步操作怎么办?Action 发出以后,Reducer 立即算出 State,这叫做同步;Action 发出以后,过一段时间再执行 Reducer,这就是异步。为了Reducer 在异步操作结束后能自动执行,这就要用到新的工具,中间件(middleware)。常用的中间件:redux-logger,redux-thunk。

5.1、中间件的用法
因为常用的中间件都有现成的,只要引用别人写好的模块即可。就以redux-thunk作为例子。
1)导入需要的组件。
2)applyMiddleware(thunk)添加。
添加多个中间件只需要逗号隔开,例如applyMiddleware(thunk, logger)
这里需要注意的是 有的中间件有次序要求,使用前要查一下文档
5.2、applyMiddlewares()
它是 Redux 的原生方法,作用是将所有中间件组成一个数组,依次执行。下面是它的源码。

export default function applyMiddleware(...middlewares) {  return (createStore) => (reducer, preloadedState, enhancer) => {    var store = createStore(reducer, preloadedState, enhancer);    var dispatch = store.dispatch;    var chain = [];    var middlewareAPI = {      getState: store.getState,      dispatch: (action) => dispatch(action)    };    chain = middlewares.map(middleware => middleware(middlewareAPI));    dispatch = compose(...chain)(store.dispatch);    return {...store, dispatch}  }}

上面,所有中间件被放进了一个数组chain,然后嵌套执行,最后执行store.dispatch。

五、Reducer 的拆分

Reducer 函数负责生成 State。由于整个应用只有一个 State 对象,包含所有数据,对于大型应用来说,这个 State 必然十分庞大,导致 Reducer 函数也十分庞大。

import {combineReducers} from 'redux';import loginIn from './loginReducer';import demoOne from './demoOneReducer';import listViewReducer from './listViewDemoReducer'const rootReducer = combineReducers({  loginIn: loginIn,  demoOne: demoOne,  listViewReducer: listViewReducer,});export default rootReducer;

拆分之后当然要合并,combineReducers方法将三个子 Reducer 合并成一个大的rootReducer。

六、React-Redux 的用法

6.1、UI 组件
React-Redux 将所有组件分成两大类:UI 组件(presentational component)和容器组件(container component)。

UI 组件有以下几个特征。

    只负责 UI 的呈现,不带有任何业务逻辑    没有状态(即不使用this.state这个变量)    所有数据都由参数(this.props)提供    不使用任何 Redux 的 API

6.2、容器组件
容器组件的特征恰恰相反。

    负责管理数据和业务逻辑,不负责 UI 的呈现    带有内部状态    使用 Redux 的 API

总之,只要记住一句话就可以了:UI 组件负责 UI 的呈现,容器组件负责管理数据和逻辑。
将它拆分成下面的结构:外面是一个容器组件,里面包了一个UI 组件。前者负责与外部的通信,将数据传给后者,由后者渲染出视图。

React-Redux 规定,所有的 UI 组件都由用户提供,容器组件则是由 React-Redux 自动生成。也就是说,用户负责视觉层,状态管理则是全部交给它。

6.3、connect()

React-Redux 提供connect方法,用于从 UI 组件生成容器组件。connect的意思,就是将这两种组件连起来。

import { connect } from 'react-redux'export default connect(mapStateToProps)(LoginDemo)

6.4、mapStateToProps()

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

作为函数,mapStateToProps执行后应该返回一个对象,里面的每一个键值对就是一个映射。请看下面的例子。

const mapStateToProps = (store) => {  return {    status: store.loginIn.status,    isSuccess: store.loginIn.isSuccess,    user: store.loginIn.user  }}

mapStateToProps会订阅 Store,每当state更新的时候,就会自动执行,重新计算 UI 组件的参数,从而触发 UI 组件的重新渲染。

connect方法可以省略mapStateToProps参数,那样的话,UI 组件就不会订阅Store,就是说 Store 的更新不会引起 UI 组件的更新。

6.5、Provider 组件

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

export default class Root extends Component {  render() {    return (      <Provider store={store}>        <App />      </Provider>    );  }}

七、工作流程

这里写图片描述

原创粉丝点击