
redux是一个流行的JavaScript框架,为应用程序提供一个可预测的状态容器。在标准的MVC框架中,数据可以在UI组件和存储之间双向流动,而redux严格限制了数据只能在一个方向上流动。
是专于状态管理的库,和react解耦;
单一状态,单项数据流;
核心概念 store 、action、reducer;
redux工作流
reactComponents 要改变store里的数据时:
01
先要派发一个action,action会通过store.dispatch(action)传递给store;
02
store会把旧的state和action转发给reducer;
03
reducer是一个函数,接收到旧的state和action,做一些处理之后,会返回一个新的state给store;
04
store用新的state替换掉旧的state;
05
store改变之后,reactComponents会感知store发生改变,这时组件从store里重新取数据,更新组件内容,页面就跟着发生变化了。
为了更好的理解redux工作原理,我们可以把redux工作流程比做借书过程。
reactComponents:借书人;
store:图书管理员;
action :借书人和图书管理员说的话;
reducer:图书管理员的查书手册。
当借书人(reactComponents)想要借一本书时,会和图书管理员(store)说一句话(action),告诉管理员要借什么书,这句话有固定格式,必须包含书名(type)和其它信息(value),图书管理员(store)听到话后会去查手册(reducer),手册(reducer)会根据之前的存书数据(previousState)和这句话(action),告诉图书管理员(store)现在的存书数据(newState)是什么,管理员(store)更新数据。
redux三项原则唯一数据源
应用的状态数据应该只存储在唯一的store上。 这个唯一store上的状态,是一个树形的对象ObjectTree,每个组件往往只是用树形对象上一部分的数据。
保持状态只读
不能直接去修改状态,派发action是唯一改变store的方法。
数据改变只能通过纯函数完成
为了描述action如何改变ObjectTree,需要编写reducer,reducer必须是纯函数(函数的返回结果必须完全由参数state和action决定,不能修改参数state和action对象,而且不产生任何副作用。)
Redux小例子我们用react+redux实现一个小功能:点击“+”、“-”按钮的时候,输入框里的数字对应的+1、-1。

在开始之前,确保已经安装了Node.js、npm包管理工具(或yarn);用create-react-app生成一个“redux-demo”项目;安装了redux库。(点进来看文章的人,这些应该是没有问题的哈,就不赘述了~)
实际项目中,我们习惯用一个store文件夹来管理store。文件夹下有四个文件,其中,actionTypes.js定义action类型;actionCreators.js定义action构造函数;reducer.js定义reducer函数;index.js来创建store。因为本例较简单,所以把四个文件的内容整合在了一个store.js文件中。
store.js:
import { createStore } from 'redux';//actionTypesconst ADD_ACTION='add_action';const MINUS_ACTION='minus_action';//actionCreatorsexport const addAction=()=>({ type:ADD_ACTION})export const minusAction=()=>({ type:MINUS_ACTION})//reducersconst defaultState={ value:0};const reducer=(state=defaultState , action)=>{ switch (action.type) { case ADD_ACTION: return {...state,value:state.value+1}; case MINUS_ACTION: return {...state,value:state.value-1}; default: return state; }}//indexexport const store = createStore(reducer);
actionTypes:
定义action类型,把action类型定义为常量,有一个好处是方便出错后调试。如果action类型不用常量 ADD_ACTION而直接用字符串’add_action’,当组件中派发action时一不小心拼写错字符串,action不会正常派发,但是控制台是不会报错的。
actionCreators:
每个构造函数都返回一个action对象(使用redux中间件的时候action还可以是函数),包含type和value。
reducer:
reducer里定义了store的初始状态。
reducer函数中往往包含以action. type为判断条件的if-else或者switch语句。 reducer只用关心如何更新state,而不要管state怎么存。代码中使用了三个句点组成的扩展操作符,这表示把state中所有字段扩展开,而后面对value值对应的字段会赋上新值。
return {...state,value:state.value+1};
等同于
const newState = Object.assign({}, state);newState.value++;return newState;
像上面这样写,创造了一个newState完全复制了state,通过对newState的修改避免了对state的修改,不过这样写显得冗长,使用扩展操作符看起来更清晰简洁。
⚠️注意:reducer里不能修改state,reducer应该是纯函数,不能产生任何副作用。
index:
这个文件定义全局唯一的store。
接下来看如何在组件中获取和更新store中的数据。
app.js:
import React , { Component } from 'react';import { store , addAction , minusAction } from './store'class App extends Component{ constructor(props){ super(props); this.state=store.getState(); this.add=this.add.bind(this); this.minus=this.minus.bind(this); this.listerner=this.listerner.bind(this); } componentDidMount(){ store.subscribe(this.listerner); } componentWillUnmount() { store.unsubscribe(this.listerner); } render(){ return( <div> <button onClick={this.add}>+</button> <input type="text" value={this.state.value}/> <button onClick={this.minus}>-</button> </div> ) } listerner(){ const value=store.getState().value; this.setState({ value }) } add(){ store.dispatch(addAction()); } minus(){ store.dispatch(minusAction()); }}export default App;
在app.js中我们要引入store。
constructor中初始化this.state的数据来源于store,通过store.getState()能够获得store上存储的所有状态。
在componentDidMount函数中,我们通过store的subscribe监听其变化,只要store状态发生变化,就会调用这个组件的listerner方法,从而保持this.state和store上的状态始终一样;在componentWillUnmount函数中,我们把这个监听注销掉,这个清理动作和componentDidMount中的动作对应。其实,这个增加监听函数的语句也可以写在构造函数中,但是为了让mount和unmount的对应看起来更清晰,在本例中我们把store的subscribe函数放在componentDidMount中。
改变store中状态的唯一方法是派发action,派发action就需要调用store.dispatch函数。在render函数中,对于点击“+”按钮和“-”按钮的onClick事件,被分别挂上了add函数和minus函数,所做的事情就是派发对应的action对象出去。
常用apicreateStore :创建store。
const store = createStore(reducer);
store.dispatch :派发action。
store.dispatch(action)
store.getState :获取store里所有内容。
this.state=store.getState();
store.subscribe :监控store里的state是否改变。
store.subscribe(this.listener);
嗯,似乎再写一些redux实现原理的东西才算圆满,可是漂亮的小编有点瞌睡了,想来偷懒一下,下次再补也是可以的。🌚
