news 2026/7/6 21:35:42

redux学习笔记

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
redux学习笔记

基础方法

1、createStore

创建redux的store。支持两种形式

  • createStore(reducer, enchancer),其中reducer为Reducer类型,enhancere为StoreEnhancer
  • createStore(reducer, prelaodedState, enhancer),其中prelaodedState为PreloadedState类型

如果enhancer为函数,则直接返回enhancer(createStore)(reducer, preloadedState)

createStore创建时,没有指定enhancer时,会分发ActionTypes.INIT,返回store对象{dispatch, subscribe, getState, replaceReducer}

store对象主要有4个方法

dispatch(action: A)

根据当前状态以及行为执行currentReducer得到新的状态,触发监听器

function dispatch(action: A) { if (!isPlainObject(action)) { throw new Error( `Actions must be plain objects. Instead, the actual type was: '${kindOf( action )}'. You may need to add middleware to your store setup to handle dispatching other values, such as 'redux-thunk' to handle dispatching functions. See https://redux.js.org/tutorials/fundamentals/part-4-store#middleware and https://redux.js.org/tutorials/fundamentals/part-6-async-logic#using-the-redux-thunk-middleware for examples.` ) } if (typeof action.type === 'undefined') { throw new Error( 'Actions may not have an undefined "type" property. You may have misspelled an action type string constant.' ) } if (typeof action.type !== 'string') { throw new Error( `Action "type" property must be a string. Instead, the actual type was: '${kindOf( action.type )}'. Value was: '${String(action.type)}' (stringified)` ) } if (isDispatching) { throw new Error('Reducers may not dispatch actions.') } try { isDispatching = true currentState = currentReducer(currentState, action) } finally { isDispatching = false } const listeners = (currentListeners = nextListeners) listeners.forEach(listener => { listener() }) return action }

subscribe(listener: () => void)

订阅监听者,同时返回取消注册

function subscribe(listener: () => void) { if (typeof listener !== 'function') { throw new Error( `Expected the listener to be a function. Instead, received: '${kindOf( listener )}'` ) } 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() const listenerId = listenerIdCounter++ nextListeners.set(listenerId, listener) return function unsubscribe() { if (!isSubscribed) { return } if (isDispatching) { throw new Error( 'You may not unsubscribe from a store listener while the reducer is executing. ' + 'See https://redux.js.org/api/store#subscribelistener for more details.' ) } isSubscribed = false ensureCanMutateNextListeners() nextListeners.delete(listenerId) currentListeners = null } }

getState(): S

获取当前的状态

function getState(): S { if (isDispatching) { throw new Error( 'You may not call store.getState() while the reducer is executing. ' + 'The reducer has already received the state as an argument. ' + 'Pass it down from the top reducer instead of reading it from the store.' ) } return currentState as S }

replaceReducer(nextReducer: Reducer<S, A>): void

替换reducer,重新计算状态

function replaceReducer(nextReducer: Reducer<S, A>): void { if (typeof nextReducer !== 'function') { throw new Error( `Expected the nextReducer to be a function. Instead, received: '${kindOf( nextReducer )}` ) } currentReducer = nextReducer as unknown as Reducer<S, A, PreloadedState> // This action has a similar effect to ActionTypes.INIT. // Any reducers that existed in both the new and old rootReducer // will receive the previous state. This effectively populates // the new state tree with any relevant data from the old one. dispatch({ type: ActionTypes.REPLACE } as A) }

2、applyMiddleware

应用redux的中间件,对store作功能增强。其返回StoreEnhancer。其实现为

function applyMiddleware(...middlewares) { return (createStore) => (reducer, preloadedState) => { const store = createStore(reducer, preloadedState) const middlewareAPI = {getState: store.getState, dispatch: (action, ...args) => dispatch(action, ...args)} const chain = middlewars.map(middleware => middleware(middlewareAPI)) dispatch = compose(..chain)(store.dispatch) return {...store, dispatch} } } export default function compose(...funcs: Function[]) { if (funcs.length === 0) { // infer the argument type so it is usable in inference down the line return <T>(arg: T) => arg } if (funcs.length === 1) { return funcs[0] } return funcs.reduce( (a, b) => (...args: any) => a(b(...args)) ) }

在对middlewars遍历得到chains,当中的每一项都是二级函数

compose是调用chains顺序是从右到左依次调用

3、combineReducers

合并Reducer,对多个reducer作统一处理,返回函数function combination(state:StateFromReducerMapObject<typeof reducers>, action:AnyAction):state

export type ReducersMapObject<S = any, A extends Action = AnyAction> = { [K in keyof S]: Reducer<S[K], A> }

可以理解为S的key作为ReducersMapObject的key,value为Reducer的函数

export type StateFromReducersMapObject<M> = M extends ReducersMapObject ? { [P in keyof M]: M[P] extends Reducer<infer S, any> ? S : never } : never

StateFromReducersMapObject添加另一个泛型M约束,M如果继承ReducersMapObject,则走{ [P in keyof M]: M[P] extends Reducer<infer S, any> ? S : never }的逻辑,否则就是never。

{ [P in keyof M]: M[P] extends Reducer<infer S, any> ? S : never }为对象,key来自M对象里面,也就是ReducersMapObject里面传入的S。key对应的value就是需要判断M[P]是否继承自Reducer,否则是never。

combineReducers函数实现为,finalReducerKeys为reducers的状态的key,finalReducers为key对应的reducer,combination函数遍历reducerKey,通过reducer计算得到当前key的状态nextStateForKey,统一放到状态对象nextState中,通过状态是否有改变返回nextState或者state。

function combination( state: StateFromReducersMapObject<typeof reducers> = {}, action: AnyAction ) { let hasChanged = false const nextState: StateFromReducersMapObject<typeof reducers> = {} for (let i = 0; i < finalReducerKeys.length; i++) { const key = finalReducerKeys[i] const reducer = finalReducers[key] const previousStateForKey = state[key] const nextStateForKey = reducer(previousStateForKey, action) nextState[key] = nextStateForKey hasChanged = hasChanged || nextStateForKey !== previousStateForKey } hasChanged = hasChanged || finalReducerKeys.length !== Object.keys(state).length return hasChanged ? nextState : state }

4、compose

函数组合调用。其实现为

function compose(...funcs:Function[]) { if (funcs.length === 0) { return (arg) => arg } if (funcs.length === 1) { return funcs[0] } return funcs.reduce((a, b) => (...args) => a(b(...args))) }

5、 Middleware

MiddlewareAPI接口包含两个方法:dispatch和getState

export interface MiddlewareAPI<D extends Dispatch = Dispatch, S = any> { dispatch: D getState: () => S }

Middleware输入为MiddlewareAPI,输出为二级函数

其类型定义为,

export interface Middleware< _DispatchExt = {}, // TODO: see if this can be used in type definition somehow (can't be removed, as is used to get final dispatch type) S = any, D extends Dispatch = Dispatch > { ( api: MiddlewareAPI<D, S> ): (next: (action: unknown) => unknown) => (action: unknown) => unknown }

redux开源中间件

  • redux-thunk
  • redux-promise
  • redux-composable-fetch
  • redux-saga

react-router-redux

将路由状态纳入redux的状态管理

React RouterRedux store绑定
import {browserHistory} from 'react-router'; import {syncHistoryWithStore} from 'react-router-redux'; import reducers from '<project-path>/reducers'; const store = createStore(reducers); const history = syncHistoryWithStore(browserHistory, store);

用redux方式改变路由

import {browserHistory} from 'react-router'; import {routerMiddleware} from 'react-router-redux'; const middleware = routerMiddleware(browserHistory); const store = createStore(reducers, applyMiddleware(middleware));
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/6 21:33:33

2.2.1工具篇-Power Query——Power Query从入门到精通

“我花了80%的时间清洗数据&#xff0c;只有20%的时间分析数据。”——这曾是数据分析师的日常写照。直到Power Query的出现&#xff0c;彻底改变了这一工作模式。 一、为什么Power Query是数据分析必备技能&#xff1f; 在正式开始学习之前&#xff0c;让我们先了解Power Que…

作者头像 李华
网站建设 2026/7/6 21:33:30

常微分方程数值解法对比:4种Python算法解 y‘=y-x 的误差与效率分析

常微分方程数值解法对比&#xff1a;4种Python算法解 yy-x 的误差与效率分析在工程计算与科学研究的实际场景中&#xff0c;绝大多数微分方程无法求得解析解。以初值问题yy-x为例&#xff0c;虽然其解析解为y(x)x1Ce^x&#xff0c;但当方程右端函数变为复杂非线性形式时&#x…

作者头像 李华
网站建设 2026/7/6 21:33:04

Java反射全面详解

目录 一. 什么是反射&#xff1f; 二. 反射有什么用&#xff1f; 三. 获取 Class 字节码文件对象的三种方式&#xff08;重中之重&#xff0c;面试会问&#xff09; 3.1 Class.forName("全类名")方式获取&#xff1b; 3.2 类名.class 方式获取 3.3 对象.getCla…

作者头像 李华
网站建设 2026/7/6 21:27:25

R语言非线性建模实战:从nls失败到精准预测的完整路径

1. 这不是“又一本R语言教材”&#xff0c;而是一份用真实数据撞墙后写成的非线性建模手记你打开R&#xff0c;lm()函数敲得飞快&#xff0c;散点图上那条直线划得笔直&#xff0c;p值小于0.001&#xff0c;R高达0.87——可当你把模型拿去预测下个月的销售、下周的设备故障率、…

作者头像 李华