是全局唯一的Dispatcher对象,关系网的中心
// AppDispatcher.js
// 完成声明即可,后续无需改动
// 注册action等事件主要在store中被调用完成
import {Dispatcher} from 'flux';
export default new Dispatcher ();
注册(register):把当前store注册到Dispatcher下,加入dispatcher关系网
通过emit广播、on挂载事件
store需要注册到全局唯一的Dispatcher上才有效
flux核心部分:当register函数把一个回调函数注册到Dispatcher后,所有派发给Dispatcher的action对象,都会传递到这个回调函数中
const counterValues = {
'First': 0,
'Second': 10,
'Third': 30
}
// 声明、生成store对象
const CounterStore = object.assign({}, EventEmitter.prototype, {
getCounterValues: function() {
return counterValues;
},
emitChange: function(){
this.emit(CHANGE_EVENT); // 广播事件
},
addChangeListener: function(){
this.on(CHANGE_EVENT, callback); // 挂载事件
},
removeChangeListener: fucntion(){
this.removeListener(CHANGE_EVENT, callback); // 移除监听
}
})
// 把CounterStore注册到全局唯一的Dispatcher上,register函数接受一个回调函数做参数
//注册token(控制权令牌)
CounterStore.dispatchToken = AppDispathcer.register((action)=>{
if(action.type === ActionTypes.INCREMENT){
// do increment
// 根据action对象,修改当前store中的counterValues变量
} else if(action.type === ActionTypes.DECREMENT){
// do decrement
// 根据action对象,修改当前store中的counterValues变量
}
})
使用waitFor()函数,通过dispatchToken的传递,实现同步调用,满足多个store之间的相互依赖关系;
常用于获取store中的最新鲜的数据
代表一个动作的纯数据对象
是js对象,且不自带方法,用于驱动Dispatcher,来自用户的请求
Action并不包含数据处理逻辑,而是调用函数,来创建对应的action对象
// ActionTypes.js
export const INCREMENT = 'increment';
export const DECREMENT = 'decrement';
// action.js
import * as ActionTypes form './ActionTypes.js';
import AppDispatcher from './AppDispatcher.js'
export const increment = (counterCaption) => {
AppDispatcher.dispatch({
type: ActionTypes.INCREMENT, // action对象类型
counterCaption:counterCaption // 用于标识发出action的来源(即页面元素)
})
}
用户在界面中调用action
// react组件中的事件
onClickBtn() {
// increment已经在对应的store中完成注册,Dispactcher可识别
Actions.increment(this, props.caption);
}
Dispatcher:
在十字路口中央指挥交通的交警,不会离开工作地点,是唯一的;
当有人督促我派发(dispatch)一下action,我就要打电话给我的小协警了,叫他赶紧来把这个家伙的事处理一下;
Store:
注册:协警把自己的电话号码给了十字路口的交警并告诉他:“发生交通事故,就打这个电话找我,我来处理现场”;
emit广播事件:有人叫我去处理交通事故;
on挂载事件:如果有人叫我去处理交通事故,我要给出的反应;
view:
路上的车主,一旦和别人的车撞上了,我要发出一个action(下车跑去找交警告诉交警我的事故属于哪种类型)让交警知道我撞车了,不然他不会理我的;
action:
车主督促交警,赶紧把我的action派发(dispatch)出去,让协警快来处理一下;
flux的目的:纠正MVC框架的无法禁绝view与model通信的缺点;
flux的做法:store只有get方法,没有set方法;因此view只能通过get获取store状态,不能修改状态;如果想要修改store状态,只能派发一个action给Dispatcher,由action中ActionTypes对应的store方法去修改store本身。
flux的缺点:
Flux:利用Dispatcher的waitFor方法,保证多个store之间的依赖与更新顺序 ==> 数据冗余、应用复杂
Redux:所有state只保存在一个store中,整个应用只有一个store,状态是一个树形对象,每个组件使用状态树上的一部分数据
状态只可读,不可直接修改
渲染原则:UI = render(state) <===> 界面只根据State进行渲染
与Flux相同,必须通过action对象才能修改store状态
纯函数:指不依赖于且不改变它作用域之外的变量状态的函数,也就是说函数的返回结果必须完全由传入的参数决定。
reducer(state, action)
reducer函数,接受两个参数,第一个参数state是当前的状态(最新的store.state),第二个参数action是接收到的action对象;reducer根据state与action的值产生并返回一个新的对象,返回的这一个对象用来组装新状态对象。
在Flux中,Dispatcher的作用:把action对象分发给不同的、已注册的store;
在redux中,只有一个store,是唯一的分发对象,因此将Dispatcher对象简化为store对象中的一个函数dispatch。
使用createStore创建整个应用唯一的store,并且暴露到全局;
组件使用getOwnState函数用于从store中获得状态
import {createStore} from 'redux';
import reducer from './Reducer.js';
const counterValues = {
'First': 0,
'Second': 10,
'Third': 20
}
const store = createStore(reducer, initValues); // reducer表示更新状态的reducer,initValues是状态的初始值
export default store;
reducer <===> redux与flux对state的操作差异:
flux:直接修改state的值
redux:修改应用状态,并不能直接修改状态上的值,而是创建一个新的状态对象返回给Redux,由Redux组装新状态对象。
// Flux版本的action
// Flux: 直接修改store状态值
CounterStore.dispatchToken = AppDispatcher.register( (action) => {
if(action.type === AcitonTypes.INCREMENT) {
counterValues[action.counterCaption]++;
CounterStore.emitChange();
} else if(action.type === AcitonTypes.DECREMENT){
counterValues[action.counterCaption]--;
CounterStore.emitChange();
}
})
// Redux版本的action
// 根据state与action的值产生并返回一个新的对象
// 返回的这一个对象用来组装新状态对象。
function reducer (state,action) {
const {counterCaption} = action;
// 返回的对象是一个新的状态树
// ... 扩展操作符
// ...state表示扩展拆分state数据,去除了最顶层的树结构,暴露二级节点
// [counterCaption]: newData 则体现了redux状态树的设计
// 使用组件的caption作为状态树的对应子数据字段
switch (action.type) {
case ActionTypes.INCREMENT:
return {...state, [counterCaption]: state[counterCaption] +1};
case ActionTypes.DECREMENT:
return {...state, [counterCaption]: state[counterCaption] -1};
default:
return state
}
}
flux:Action构造函数不返回什么,而是把构造的动作函数立刻通过调用dispatcher函数派发出去
// Flux之Action
export const increment = (counterCaption) => {
AppDispatcher.dispatch({
type: ActionTypes.INCREMENT, // action对象类型
counterCaption:counterCaption // 用于标识发出action的来源(即页面元素)
})
}
reudx:每个Action构造函数返回一个action对象 == > 返回一个对象,把处理对象的工作交给调用者
// Redux之Action
export const increment = (counterCaption) => {
return {
type: ActionTypes.INCREMENT, // action对象类型
counterCaption:counterCaption // 用于标识发出action的来源(即页面元素)
})
}
用于声明绑定派发action事件
onIncrement() {
// 通过dispatch派发aciton
store.dispatch(Actions.increment(this.props.caption));
}
render() {
const value = this.state.value;
const {caption} = this.props;
return (
<div>
<button onclick={this.onIncrement}>+</button>
</div>
);
}
当前组件具有两个功能:1、派发Action,更新state树;2、根据state与props渲染用户界面
为了使组件专注于单一功能 ===> 拆分组件(容器组件、展示组件)
容器组件:外层组件,负责与store交互;
展示组件:内层组件,负责渲染界面,无状态;
store 《====》 容器组件 ===(传递props)==》 展示组件 《====》 React界面
理想目标:
单个应用最好只导入一次全局Store,在最顶层React组件的位置;
为提高组件的复用性,其余组件应该避免直接导入Store;
为了满足以上原则而出现的缺点:在一个多层嵌套组件结构中,当只有最里层组件需要使用store,为了将sotre从最外层传到最里层,必须在所有中间组件中使用props逐级传递state。
Context:在树状组件中的所有组件都可访问的一个共同对象,上下文环境
当上级组件宣称自己支持context,并且提供一个函数来返回代表context的对象,所有子孙组件可在宣称(import)后通过this.context访问到这个共同的环境变量。
Provider类组件实现Context
// Provider类组件实现Context
import {PropTypes, Component} from 'react';
class Provider extends Component {
getChildContext() {
return {
store: this.props.store
};
}
render() {
// 渲染子组件 props.children代表子组件
return this.props.children;
}
}
// 使Provider被React认可,成为一个Context提供者,必须指定childContextTypes属性
Provider.childContextTypes = {
store: PropTypes.object
};
Provider提供Context,暴露到所有子组件中
// Provider的实践使用
// index.js 应用入口文件
import store from './Store.js'
import Provider from './Provider.js';
// ControlPanel是Reactdom的顶层组件,现在被Provider组件包住后,Provider成为顶层组件
// Provider内层包裹的所有
ReactDOM.render (
<Provider store={store}>
<ControlPanel />
</Provider>,
document.getElementById('root')
)
在子组件中使用Context
// 第一步: 给组件类的contextTypes属性赋值
CounterContainer.contextTypes = {
store: PropTypes.object
}
// 第二步:在构造函数中用上第二个参数context
constructor(props, context) {
// 写法一:
super(props, context);
// 写法二:
super(...arguments);
}
// 第三步:通过this.context.store访问store
getOwnState() {
return {
// [this.props.catption]用于获取状态树中的某个二级状态
value: this.context.store.getState()[this.props.catption]
}
}
对于Redux的两个改进在实现在实现上仍然具有一定的复杂性与机械性,因此已经有人创建了一个库来帮我们完成这些工作(组件拆分与context)
react-redux库两大功能:
1、connect:连接容器组件与展示组件
2、Provider:我们不再需要自己实现Provider来获取context,可以使用库提供的Provider
包含了两个函数中执行:connect与connect返回函数
connect(mapStateToProps, mapDispatchToProps)的传入参数是两个映射函数,返回值是一个函数
connect函数作用:
1、向内传递state:把store上的状态转化为内层展示组件的props;
2、向外转发Action:把内层展示组件中的用户动作转化为派送给store的动作
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
// mapStateToProps函数,向内传递state => props
function mapStateToProps(state, ownProps) {
return {
value: state[ownProps.caption]
}
}
// mapDispatchToProps函数,向外转发Action
// ownProps属性就是,直接传递给外层容器组件的props
function mapDispatchToProps(dispatch, ownProps) {
return {
onIncrement: () => {
dispatch(Actions.increment(ownProps.caption));
},
onDecrement: () => {
dispatch(Actions.decrement(ownProps.captions))
}
}
}
import {Provider} from 'react-redux';
react-redux库的提供的Provider几乎相同,但更加严谨;
react-redux库要求store必须是一个包含以下三个函数的object:
react-redux还提供了componentWillReceiveProps钩子,用于每次重新渲染时调用
React项目实战:react-redux-router基本原理,Redux 的 React 绑定库包含了 容器组件和展示组件相分离 的开发思想。明智的做法是只在最顶层组件(如路由操作)里使用 Redux。其余内部组件仅仅是展示性的,所有数据都通过 props 传入。
Redux:状态管理工具,与React没有任何关系,其他UI框架也可以使用Redux,react-redux:React插件,作用:方便在React项目中使用Redux,react-thunk:中间件,作用:支持异步action
compose,英文意思 组成,构成。它的作用也是通过一系列的骚操作,实现任意的、多种的、不同的功能模块的组合,用来加强组件。很容易实现功能的组合拼装、代码复用;可以根据需要组合不同的功能;
这里要讲的就是一个Redux在React中的应用问题,讲一讲Redux,react-redux,redux-thunk,redux-actions,redux-promise,redux-sage这些包的作用和他们解决的问题。
最近几天对 redux 的中间件进行了一番梳理,又看了 redux-saga 的文档,和 redux-thunk 和 redux-promise 的源码,结合前段时间看的redux的源码的一些思考,感觉对 redux 中间件的有了更加深刻的认识,因此总结一下
类似于 Vue,React 中组件之间的状态管理 第三方包为:react-redux。react-redux 其实是 Redux的官方React绑定库,它能够使你的React组件从Redux store中读取数据,并且向store分发actions以更新数据。
看到“reducer”这个词,容易让人联想到Redux,但是在本文中,不必先理解Redux才能阅读这篇文章。咱们将一起讨论“reducer”实际上是什么,以及如何利用useReducer来管理组件中的复杂状态,以及这个新钩子对Redux意味着什么?
我在读React-Redux源码的过程中,很自然的要去网上找一些参考文章,但发现这些文章基本都没有讲的很透彻,很多时候就是平铺直叙把API挨个讲一下,而且只讲某一行代码是做什么的,却没有结合应用场景和用法解释清楚为什么这么做。
我的许多同事最近通过各种方式问同一类问题:“如果我们开始用 hook 后,那还有必要用 Redux 吗?”“React hook 不是让 Redux 过时了吗?那只用 Hooks 就可以做 Redux 所有能做的事了吧?”
redux是react的状态管理工具,却不仅仅只是为了react而生的,所以在使用中会存在痛点。而react-redux是专门为了react定制,目的是为了解决redux的痛点,起到了补充的作用。flux无非就是一个常见的event dispatcher
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!