内容简介:不能因为别人怀疑自己,但是可以通过别人启发自己 !昨天有人让我把他当小白讲讲redux,我表示理出来的逻辑并不是很明确,他可能是在教我如何写文章吧,我对自己写的东西,并不是很负责,目的一直停留在增强自己的短时间记忆,我会安排时间将之前的文章做逻辑性梳理,当然先从这篇开始。我们知道react组件传递是单向的,如果组件关系太远,或者没有关系,我们就会很麻烦,redux就是解决这个问题,他将数据存储到仓库,通过reducer派发action动作,来substrict
不能因为别人怀疑自己,但是可以通过别人启发自己 !
昨天有人让我把他当小白讲讲redux,我表示理出来的逻辑并不是很明确,他可能是在教我如何写文章吧,我对自己写的东西,并不是很负责,目的一直停留在增强自己的短时间记忆,我会安排时间将之前的文章做逻辑性梳理,当然先从这篇开始。
我们知道react组件传递是单向的,如果组件关系太远,或者没有关系,我们就会很麻烦,redux就是解决这个问题,他将数据存储到仓库,通过reducer派发action动作,来substrict
redux组成有5个
- createStore 创建仓库,接受reducer作为参数
- bindActionCreator 绑定store.dispatch和action 的关系
- combineReducers 合并多个reducers
- applyMiddleware 洋葱模型的中间件,介于dispatch和action之间,重写dispatch
- compose 整合多个中间件
createStore
主要导出getState,dispatch,subscribe三个方法,分别是获取仓库,派发动作和订阅事件。生成store,他包含所有数据,拿数据通过getState获取, 一个 State 对应一个 View。只要 State 相同,View 就相同。
其内部保存啦一颗状态树,这个状态树是任意类型的,当获取状态树的时候后会复制一份状态树吗,并导出,防止对状态树的恶意更改。
因此,只能通过派发dispatch更改状态,dispatch会调用reducer处理action 动作,reducer是个函数,他有state和action两个参数,作用是将老得state经过action处理后返回新的state,action是个有type属性的对象,来标示他对哪个状态进行改变
于此同时,当状态发生改变会触发subscribe订阅的监听事件
export default function createStore(reducer,initState,enchancer) { if (enchancer) { return enchancer(createStore)(reducer,initState); } //仓库内部保存了一颗状态树。可以是任意类型 let state; let listeners=[]; function getState() { return JSON.parse(JSON.stringify(state)); } //组件可以派发动作给仓库 function dispatch(action) { //调用reducer进行处理,获取老的state,计算出新的state state=reducer(state,action); //通知其他的组件 listeners.forEach(l=>l()); } //如果说其他的组件需要订阅状态变化时间的话, function subscribe(listener) { listeners.push(listener); return function () { listeners = listeners.filter(item=>item!==listener); } } dispatch({type:'@@INIT'}); return { getState, dispatch, subscribe } } 复制代码
bindActionCreator
虽然我们用dispatch派发事件,派发动作类型大概是一个有type属性的对象,我们将这个对象的方法封一个actions的文件夹,在dispach的时候直接调用action,列入将 dispatch(()=>{type:add})
,此时我们需要建立dispatch和actions的关系
<button onClick={()=>bindActions.add1(1)}>+</button>
export default function (actions,dispatch) { //actions = {add(){return {type:ADD}},minus(){return {type:'MINUS'}}} return Object.keys(actions).reduce( (memo,key) => { memo[key]=(...args) => dispatch(actions[key](...args)); return memo; },{}); } 复制代码
combineReducers
返回一个函数,这个函数代表合并后的reducer,那么他一定有两个参数,最终返回新状态,我们迭代reducers每一个属性
//因为redux应用只能有一个仓库,只能有一个reducer //把多个reducer函数合并成一个 export default function (reducers) { //返回的这个函数就是合并后的reducer return function (state={},action) { let newState={}; for (let key in reducers) { // key=counter1 //reducers[counter1]=counter那个reducer //state合并后的状态树 //if (key===action.name) { newState[key]=reducers[key](state[key],action);//state[key]老状态 //} } return newState; } } 复制代码
我们可以发现,每个组件都需要获取仓库,管理订阅,向仓库派发事件,这样很融于,我们需要复用这样的逻辑,可以用高阶组件,或者将函数作为子组件,我们此时用这个库
applyMiddleware
中间件大概是redux里面比较难理解的部分啦
他的原理如上图,state和dispatch构成啦我们的仓库,我们可以向仓库发送action通过reducer改变状态,状态改变之后可以修改视图,用户可以通过鼠标点击视图,视图派发action,改变状态,形成循环,,有时候我们需要发布异步操作,想在派发前,派发后做一些额外动作,此时我们就需要插入中间件,我们的方法就是得到dispatch方法,重写dispacth,这里用到啦我们说的源码解析
一个redux中间件大概就是如下,之后可能会将redux和express和koa中间件做个对比给大家总结一下
function logger(store){//getState ,新的dispatch return function(next){//store.dispatch旧的 return function action(){ console.log('old'); next() console.log('new') } } } //解析过程 let logger = store => next =>action =>{ } //以下是处理过程 function applyMiddleware(middleware){ return function(creacteStore){ return function(reducer){ let store = creacteStore(reducer); let middleware2 = middleware(store) let dispatch = middleware2(store.dispatch) } } } let store = applyMiddleware(logger)(creacteStore)(reducer) 复制代码
import compose from './compose'; export default function (...middlewares) { return function (createStore) { return function (reducers) { let store=createStore(reducers);//这就是原始的仓库 dispatch 就是原始的dispatch let dispatch;//dispatch方法指向新的dispatch方法 let middlewares2 = middlewares.map(middleware=>middleware({ getState: store.getState, dispatch:action=>dispatch(action) }));//调用第一层去掉 dispatch=compose(...middlewares2)(store.dispatch);//再调用第二次把第二层去掉 return { ...store, dispatch } } } } 复制代码
compose整合中间件
function add1(str) { return 1+str; } function add2(str) { return 2+str; } function sum(a,b) { return a+b; } //let ret=add1(add2(add3('zdl'))); //console.log(ret); function compose1(...fns) {//[add1,add2,add3] return function (...args) { let last=fns.pop(); return fns.reduceRight((val,fn)=>fn(val),last(...args)); } } export default function(...fns) { return fns.reduce((a,b)=>(...args)=>a(b(...args))); } /** * 第一次的时候 a =add1 b=add3 let ret = add1(add2(...args)) * 第二次的时候 (...args)=>add1(add2(sum(...args))) */ let ret=compose(add1,add2,sum)('a','b'); console.log(ret);//123zdl 复制代码
react-redux
有四个文件
- connect 将store和dispatch分别映射成props属性对象,返回组件
- context 上下文 导出Provider,,和 consumer
- Provider 一个接受store的组件,通过context api传递给所有子组件,优点类似于路由啦
- index
index
import Provider from './Provider'; import connect from './connect'; export { Provider, connect } 复制代码
Provider
/** * 是一个组件,用来接受store,再经过它的手通过context api传递给所有的子组件 */ import React,{Component} from 'react' import {Provider as StoreProvider} from './context'; import PropTypes from 'prop-types'; export default class Provider extends Component{ //规定如果有人想使用这个组件,必须提供一个redux仓库属性 static propTypes={ store:PropTypes.object.isRequired } render() { let value={store:this.props.store}; return ( <StoreProvider value={value}> {this.props.children} </StoreProvider> ) } } 复制代码
context
import React from 'react' let {Provider,Consumer}=React.createContext(); export {Provider,Consumer}; 复制代码
connect
这是个高阶函数,分别传入两个方法mapStateToProps,mapDispatchToProps,将store和dispatch分别映射成props属性对象,这样在页面就不需要饮用仓库,也不需要绑定action和dispatch,也不需要订阅状态,返回组件
import {Consumer} from './context'; import React,{Component} from 'react'; import {bindActionCreators} from '../redux'; /** * connect实现的是仓库和组件的连接 * mapStateToProps 是一个函数 把状态映射为一个属性对象 * mapDispatchToProps 也是一个函数 把dispatch方法映射为一个属性对象 */ export default function (mapStateToProps,mapDispatchToProps) { return function (Com) { //在这个组件里实现仓库和组件的连接 class Proxy extends Component{ state=mapStateToProps(this.props.store.getState()) componentDidMount() { this.unsubscribe = this.props.store.subscribe(() => { this.setState(mapStateToProps(this.props.store.getState())); }); } componentWillUnmount = () => { this.unsubscribe(); } render() { let actions={}; //如果说mapDispatchToProps是一个函数,执行后得到属性对象 if (typeof mapDispatchToProps === 'function') { actions = mapDispatchToProps(this.props.store.dispatch); //如果说mapDispatchToProps是一个对象的话,我们需要手工绑定 } else { actions=bindActionCreators(mapDispatchToProps,this.props.store.dispatch); } return <Com {...this.state} {...actions}/> } } return () => ( <Consumer> { value => <Proxy store={value.store}/> } </Consumer> ); } } 复制代码
以上所述就是小编给大家介绍的《redux && react-redux源码解析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- ReactNative源码解析-初识源码
- Spring源码系列:BeanDefinition源码解析
- Spring源码分析:AOP源码解析(下篇)
- Spring源码分析:AOP源码解析(上篇)
- 注册中心 Eureka 源码解析 —— EndPoint 与 解析器
- 新一代Json解析库Moshi源码解析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
XML 在线格式化
在线 XML 格式化压缩工具
RGB HSV 转换
RGB HSV 互转工具