Redux的作用是什么
Redux
的作用在于实现状态传递
、状态治理
。在这里你可能会说了,如果是状态传递
,那我props
的传递不也是能够达到这样的成果吗?context上下文计划
不也是能够达到这样的成果吗?没错,是这样的,然而上述的两种计划是有局限性
的。
props
计划只实用于父子组件传递状态。context
上下文计划尽管可能在根组件上定义上下文,然而有两种缺点- 只有上下文外面的状态产生扭转,就会从新渲染整个组件树,进而会产生宏大的性能开销。
- 组件的逻辑与状态的
耦合度
太高,不利于解耦,也就是无奈实现对状态的对立治理。
既然Redux
的作用是对状态的治理与传递,那么他的作用场景呢?当然了你能够依据下面说的两种计划对Redux
的应用做取舍,Redux
的实质就是全局变量被协调治理。
- 如果波及多个状态,且多个状态会被多个组件应用到,比方商城购物车场景,你就能够毫不犹豫的思考用
Redux
。 - 如果波及多个状态,然而状态虽多然而是用的组件惟一,或者有关联关系的组件应用,你就大可不必应用
Redux
,如果状态不是那么多,那就更不用应用Redux
了。
除此之外,Redux
还有一个长处就是,不仅仅是React
自身可能应用,就连别的框架,比方jQuery
、kerry_dom
、vue
等都能够应用,然而比照于vue
来讲的话,vue有本人比拟好的的状态治理库vuex
,好了废话不多说了,咱们先来看看Redux
在我的项目中是如何是用的。
Redux的应用
// store.jsimport { createStore } from "redux";import reducer from "./reducer";export default createStore(reducer);// reducer.jsimport {cloneDeep} from 'lodash';const initilaValue = { count: 0};const reducer = (state = initilaValue, action) => { state = cloneDeep(state) const { type, payload } = action; switch (type) { case "add": state.count += payload; break; case "reduce": state.count -= payload; break default: } return state;};export default reducer;// App.jsimport React, {Component} from 'react';import store from "./store";export default class App extends Component { componentDidMount() { //reducer不会触发页面变动,须要state来触发 store.subscribe(() =>{ this.setState(store.getState()) }) } render() { //获取reducer数据 const {count} = store.getState() return ( <div> <div type='primary' onClick={this.reduce}>-</div> <span>{count}</span> <div type='primary' onClick={this.add}>+</div> </div> ); } reduce = () => { //告诉reducer页面数据变动了 store.dispatch({ type: 'reduce', payload: 1 }) } add = () => { //告诉reducer页面数据变动了 store.dispatch({ type: 'add', payload: 1 }) }}
上述代码就能够实现count
的加减计算了,咱们能够看到有几处须要留神的中央。
store.js
文件外面的createStore
。reducer.js
文件外面的cloneDeep
、return state
、state = initialValue
。App.js
文件外面的dispatch
、getState
、type
、payload
。
很显著createStore
的作用就是创立仓库,getState
为获得以后的state
值,dispatch
为某个操作之后派发给store
去更新某个state
,type
为具体的某种交互,payload
为每次交互的具体内容。各位同学能够看失去我在reducer
中做了一次state
的深克隆,这是为什么呢?是因为在每一次的action
中咱们拿到的是同一个state
的内存地址
,咱们的冀望是不论你在switch
中如何更改state
然而我不心愿在这一步就扭转了公共状态中的count
,只有在我return
的时候才会去更改真正的公共状态,也就是说reducer
函数执行产生的公有闭包外面的公共状态信息。而state = initialValue
这一步的操作就是第一次派发的时候,reducer
接管的state
为空,咱们把根底值赋给它。理解了这么多,咱们还是去看一下他的源码是如何实现的吧。
Redux的源码
//Redux/redux/src/index.tsexport { createStore, // 创立仓库api combineReducers, // 合并Reducer bindActionCreators, // 转化action applyMiddleware, // 中间件利用计划 compose,// 函数组合 __DO_NOT_USE__ActionTypes}
下面的index.ts
文件夹外面暴露出了几个api
,咱们次要针对createStore
看看。
export default function createStore( reducer: Reducer<S, A>, preloadedState?: PreloadedState<S> | StoreEnhancer<Ext, StateExt>, enhancer?: StoreEnhancer<Ext, StateExt>): Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext { // createStore函数不反对第二三四参数为函数 // 详见https://redux.js.org/tutorials/fundamentals/part-4-store#creating-a-store-with-enhancers if ( (typeof preloadedState === 'function' && typeof enhancer === 'function') || (typeof enhancer === 'function' && typeof arguments[3] === 'function') ) { throw new Error( ... ) } // 第二参数是函数,且第三参数不传 if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') { enhancer = preloadedState as StoreEnhancer<Ext, StateExt> preloadedState = undefined } // 有第三参数且不是函数 if (typeof enhancer !== 'undefined') { if (typeof enhancer !== 'function') { throw new Error( `Expected the enhancer to be a function. Instead, received: '${kindOf( enhancer )}'` ) } return enhancer(createStore)( reducer, preloadedState as PreloadedState<S> ) as Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext } // 如果reducer不是函数,要报错 if (typeof reducer !== 'function') { throw new Error( `Expected the root reducer to be a function. Instead, received: '${kindOf( reducer )}'` ) } let currentReducer = reducer // 以后的reducer let currentState = preloadedState as S // 以后的state let currentListeners: (() => void)[] | null = [] // 事件池 let nextListeners = currentListeners let isDispatching = false // 正在派发 /** * This makes a shallow copy of currentListeners so we can use * nextListeners as a temporary list while dispatching. * * This prevents any bugs around consumers calling * subscribe/unsubscribe in the middle of a dispatch. */ function ensureCanMutateNextListeners() { if (nextListeners === currentListeners) { nextListeners = currentListeners.slice() } } // 返回以后的state function getState(): S { if (isDispatching) { throw new Error( ... ) } return currentState as S } //向事件池中增加更新事件 function subscribe(listener: () => void) { // 校验是不是函数 if (typeof listener !== 'function') { throw new Error( ... ) } if (isDispatching) { throw new Error( 'You may not call store.subscribe() while the reducer is executing. ' + 'If you would like to be notified after the store has been updated, subscribe from a ' + 'component and invoke store.getState() in the callback to access the latest state. ' + 'See https://redux.js.org/api/store#subscribelistener for more details.' ) } let isSubscribed = true //防止反复增加 ensureCanMutateNextListeners() nextListeners.push(listener) //subscribe函数每执行一次,都会返回一个unsubscribe用来从事件池中移除以后事件 return function unsubscribe() { if (!isSubscribed) { return } if (isDispatching) { throw new Error( ... ) } isSubscribed = false ensureCanMutateNextListeners() // 移除以后事件 const index = nextListeners.indexOf(listener) nextListeners.splice(index, 1) currentListeners = null } } // 派发函数 function dispatch(action: A) { // 如果传过来的action不是对象报错 if (!isPlainObject(action)) { throw new Error( ... ) } //每一个action中都须要一个type字段,没有就报错 if (typeof action.type === 'undefined') { throw new Error( ... ) } //正在派发中.. if (isDispatching) { throw new Error('Reducers may not dispatch actions.') } try { isDispatching = true // 执行reducer,扭转state currentState = currentReducer(currentState, action) } finally { isDispatching = false } // dispatch告诉事件池去执行事件,遍历执行 const listeners = (currentListeners = nextListeners) for (let i = 0; i < listeners.length; i++) { const listener = listeners[i] listener() } return action } // 替换replaceReducer function replaceReducer<NewState, NewActions extends A>( nextReducer: Reducer<NewState, NewActions> ): Store<ExtendState<NewState, StateExt>, NewActions, StateExt, Ext> & Ext { // 入参不是函数,报错 if (typeof nextReducer !== 'function') { throw new Error( ... ) } ... // 刚开始进来要派发一次,同步state,其中{ type: ActionTypes.REPLACE }为惟一标识 // 假使不为惟一标识的话,那可能一开始就毁坏了状态value dispatch({ type: ActionTypes.REPLACE } as A) // change the type of the store by casting it to the new store return store as unknown as Store< ExtendState<NewState, StateExt>, NewActions, StateExt, Ext > & Ext } ... // 初始化store的时候,须要派发一次同步state dispatch({ type: ActionTypes.INIT } as A) const store = { dispatch: dispatch as Dispatch<A>, subscribe, getState, replaceReducer, [$$observable]: observable } as unknown as Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext // 返回仓库 const store = createStore({count:0}) return store}
参考React实战视频解说:进入学习
的确短短几百行代码实现了redux
,为此咱们也来实现一个简易版的redux
示意敬意,咱们的redux
只实现getState
、dispatch
、createStore
办法。
// myReduximport {cloneDeep} from 'lodash'export function createStore(reducer) { if(typeof reducer !== 'function') { throw new Error('reducer must be an function') } let state, listeners = []; const getState = () => { // 深克隆一个state return cloneDeep(state); } const subscribe = (listener) => { if(typeof listener !== 'function'){ throw new Error('listener must be an function') } //去重 if(!listeners.includes(listener)){ listeners.push(listener) } // 源码外面执行subscribe,返回一个卸载函数 return function unsubscribe(){ listeners.filter(action => action!== listener) } } const dispatch = (action) => { if(typeof action !== 'object' && action !== null){ throw new Error('action must be a object') } // 判断有没有type if(typeof action.type === undefined){ throw new Error('action.type must existence') } //执行 try { state = reducer(state, action) } catch (error) { //... } // 告诉事件池中的办法执行 listeners.forEach(listener=>{ if(typeof listener === 'function'){ listener(); } }) } //第一次进来要派发一次,同步初始状态 dispatch({ type:typeof Symbol !== undefined ? Symbol('ABC') : '惟一值' }) // 暴露出办法 return { getState, dispatch, subscribe }}
各位能够去codeSandBox下面去实际一下,当然了这只是简易版的redux
,官网举荐应用react-redux来进行理论的我的项目开发,因为他只关注于数据管理。
总结
redux
的大抵工作流如此: