☰
Rematch config.redux 配置详解:定制 Redux 的 initialState、reducer 合并、中间件与 Devtools
2026/9/25 5:38:28 网站建设 项目流程
  • 前端

【免费下载链接】rematch

The Redux Framework

项目地址:https://gitcode.com/gh_mirrors/re/rematch
点击查看免费下载

Rematch 在创建 store 时封装了 Redux 的整套创建流程,而init()的redux属性是打开这层封装的唯一入口。本文覆盖config.redux的全部九个配置项——initialState、reducers、middlewares、enhancers、rootReducers、combineReducers、createStore、devtoolOptions、devtoolComposer——并对照 核心包源码 与测试用例说明每项配置在 Rematch 内部的真实落点,帮助你从「纯 Redux 迁移、自研插件、注入中间件」三类场景安全地完成 Redux 层定制。

适用对象:谁需要 config.redux

官方文档(docs/api-reference/redux.md)对此有明确界定:除非你在从纯 Redux 迁移、编写自己的插件或添加中间件,否则这一节大概率与你无关。对于绝大多数 Rematch 用户,模型(model)体系已经覆盖了日常需求;而如果你只是想给 store 引入某个 Redux 生态库(如 react-redux 的 enhancer 等组合方式),仓库提供了专门的配方文档 redux plugins 配方,其优先级高于直接改写 Redux 层。

从 init 的类型定义 可以看到,InitConfig包含name、models、plugins与redux四个可选字段,其中redux字段类型为InitConfigRedux,这是「获得对 Rematch 内部 Redux 配置方式的完全控制权并覆盖任何默认值」的官方通道(见 InitConfigRedux 注释)。

基本用法:把 redux 配置传给 init

所有 Redux 定制都通过向init()传入config.redux完成。官方文档给出的完整示例如下,逐项对应后文的配置项说明:

import { init } from '@rematch/core' const store = init({ redux: { initialState: { example: 12 }, reducers: { someReducer(state, action) { switch (action.type) { default: return state } }, }, enhancers: [customEnhancer()], middlewares: [customMiddleware()], rootReducers: { RESET: (state, action) => {}, }, combineReducers: customCombineReducers, createStore: customCreateStore, devtoolOptions: customDevtoolOptions, devtoolComposer: customDevtoolComposeFunction, }, })

init()的实现非常薄:它调用createConfig()把用户输入补全为完整配置,再交给createRematchStore()构建 store,见 packages/core/src/index.ts#L8-L16。

配置项逐项解析

initialState:预置根状态

类型:any。作为 store 的初始状态传入。官方文档提醒:这通常没有必要,因为模型自身的state会覆盖对应 slice 的初始状态——每个模型的 reducer 都以model.state作为自己的默认值(createModelReducer 中state = model.state)。

它的实际用途是为不属于任何模型的 reducer 提供初始状态(配合下面的reducers使用,典型场景是迁移旧 Redux 代码库)。在源码中,initialState会被直接透传给createStore的第二个参数(preloadedState),且当其为undefined时回退为空对象:

// packages/core/src/reduxStore.ts const bagInitialState = bag.reduxConfig.initialState const initialState = bagInitialState === undefined ? {} : bagInitialState return createStore(rootReducer, initialState, enhancers)

见 packages/core/src/reduxStore.ts#L36-L43。另外,createConfig 还支持插件通过plugin.config.redux.initialState向根状态注入初始值,并与用户配置做浅合并(用户配置优先),这是插件包扩展根状态的官方机制。

reducers:挂载非模型的 reducer

类型:{ [string]: (state, payload) => any }。用于传入不属于任何模型的 reducer 函数。官方文档标注这并不推荐,但它正是从 Redux 代码库渐进迁移时的关键通道——把旧代码中的 slice reducer 逐个挂进来,同时用 Rematch 模型接管新逻辑。

这些 reducer 与所有模型的 reducer 最终汇入同一个映射表,再由combineReducers合并成根 reducer。从源码流程看(createReduxStore):

  1. 先遍历bag.models,把每个模型编译成「按 action 名路由」的组合 reducer,写入bag.reduxConfig.reducers[model.name](createModelReducer 末尾);
  2. 再调用mergeReducers()用combineReducers合并reduxConfig.reducers(此时已同时包含用户传入的非模型 reducer、各模型 reducer 以及插件合并进来的 reducer),见 mergeReducers;
  3. 特别地,若最终没有任何 reducer,mergeReducers返回一个恒等函数(state) => state,而不是空合并结果(源码 L156-L158)。

createConfig 测试 验证了这条合并链路:用户配置与插件提供的reducers会被合并,且同名的用户配置 reducer 覆盖插件 reducer。

middlewares 与 enhancers:中间件与增强器

类型分别为Redux.Middleware[]与Redux.StoreEnhancer[]。

middlewares:最终通过Redux.applyMiddleware(...bag.reduxConfig.middlewares)组成一个 enhancer 参与 compose(源码 L27)。需要注意两点:

  • Rematch 会自动追加一个 effects 中间件(createEffectsMiddleware)来执行所有 effect,并追加每个插件createMiddleware钩子产出的中间件,这些都会追加在你传入的middlewares之后(rematchStore.ts#L30-L36);
  • createConfig 同样支持插件向middlewares数组追加条目(用户在前、插件在后),这与测试用例should apply additional redux enhancers展示的数组拼接行为一致(createConfig.test.ts#L104-L122)。

enhancers:与middlewares一起进入最终 compose。源码中的组装逻辑是:若配置了devtoolComposer,则调用它并传入(enhancers, applyMiddleware(...middlewares));否则走内置的composeEnhancersWithDevtools(devtoolOptions)(enhancers, applyMiddleware(...middlewares))(reduxStore.ts#L27-L33)。DevtoolOptions 类型 注释了这一点:__REDUX_DEVTOOLS_EXTENSION_COMPOSE__不可用时(如 SSR 环境)自动回退到Redux.compose。

Reactotron 是 enhancer 通道的典型用例,redux-devtools 配方 给出了写法:

import { init } from '@rematch/core' import Reactotron from './Reactotron.config.js' init({ redux: { enhancers: [Reactotron.createEnhancer()], }, })

rootReducers:根 reducer 上的钩子

类型:{ [string]: (state, payload) => any },以action 类型为键。它是「在根 reducer 底层设置中间件钩子」的方式:当 dispatch 的 action 类型命中rootReducers时,先把(state, action)交给该根 reducer 产出一个新状态,再把这个新状态喂给合并后的正常 reducer 链。与 middleware 的关键区别——官方文档指出:root reducer 的返回值就是下一步状态;如果返回undefined,状态会回退到各 reducer 的默认初始状态。

源码中这一机制实现为一个包裹函数(createRootReducer):

if (rootReducers && Object.keys(rootReducers).length) { rootReducer = (state, action) => { const actionRootReducer = rootReducers[action.type] if (actionRootReducer) { // 先用 root reducer 产出新状态,再交给合并 reducer 继续处理 return mergedReducers(actionRootReducer(state, action), action) } return mergedReducers(state, action) } }

未命中任何 rootReducer 时行为与普通 reducer 完全一致。文档示例中的RESET: (state, action) => {}(返回undefined)即触发「回退初始状态」的语义——这是一个可用的全局重置手段。此外,所有插件的onRootReducer钩子还会在该包裹之后进一步包装根 reducer(L138-L140),typed-state、loading 等官方插件正是借此感知根状态变化。

combineReducers:覆盖 reducer 合并方式

类型:(reducers) => reducer。用于整体替换 Redux 的combineReducers。合并函数在 mergeReducers 中按「用户优先,否则用 Redux 原版」选取:

const combineReducers = reduxConfig.combineReducers || Redux.combineReducers

测试用例直接证明了它的覆盖能力:传入一个返回常量 reducer 的combineReducers后,无论配置了多少普通 reducer,store.getState()都是42(redux.test.ts#L5-L18)。

createStore:替换 store 创建函数

类型:Redux.StoreCreator。Rematch 在创建 store 时优先使用你传入的实现(reduxStore.ts#L35):

const createStore = bag.reduxConfig.createStore || Redux.createStore

测试用例中用一个只暴露getState的假 store 工厂验证了整条链路的替换效果(redux.test.ts#L30-L41)。

devtoolOptions:Redux Devtools 选项

类型:Redux.DevtoolOptions。Rematch开箱即支持Redux Devtools:composeEnhancersWithDevtools 在浏览器环境检测到window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__且未显式禁用时,自动用扩展的 compose 并传入devtoolOptions;否则回退Redux.compose。

两个值得注意的默认值行为:

  • name默认值为 store 名。createConfig 会先写入{ name: storeName }再浅合并用户的devtoolOptions,因此不传name时 Devtools 面板显示 store 名;而 store 名本身默认是Rematch Store N(N 为自增序号,config.ts#L17-L19),适合多 store 应用区分实例。
  • disabled: true用于关闭 Devtools(如生产环境),源码中的判断顺序是!devtoolOptions.disabled && ...,即disabled优先级最高。

常用选项(完整字段及注释见 DevtoolOptions 类型):latency(批处理延迟,默认 500ms)、maxAge(历史记录上限,默认 50)、serialize(序列化模式)、actionsBlacklist/actionsWhitelist(按正则过滤 action)、predicate(逐 action 决定是否上报)、features(裁剪 Devtools 功能项)等。最小示例:

init({ redux: { devtoolOptions: { actionSanitizer: (action) => action, }, }, })

devtoolComposer:自定义 compose(远程 Devtools)

自Rematch 2.2.0起加入的配置项,类型为remote-redux-devtools风格的 compose 函数。传入后,Rematch 不再使用内置的 Devtools compose,而是把用户自带的 enhancers 和 middleware 交给你的 composer(reduxStore.ts#L28-L33),从而接入composeWithDevTools等远程调试通道。典型配置(来自 redux-devtools 配方):

import { init } from '@rematch/core' import { composeWithDevTools } from 'remote-redux-devtools' init({ redux: { devtoolComposer: composeWithDevTools({ realtime: true, hostname: 'localhost', port: 8000, }), }, })

远程调试场景下,可安装@redux-devtools/cli并添加启动脚本(redux-devtools --open=electron --hostname=localhost --port=8000)建立 SocketCluster,然后按上述配置对齐devtoolComposer的hostname/port,即可在远程 Devtools 中看到 Rematch store 的状态流。

实现层全链路:从 init 到 store

把上面各配置项串起来,Rematch 的完整处理链如下,每一步都有源码可查:

  1. 配置补全与校验:init()→createConfig()(config.ts)。它为redux填充默认值(reducers: {}、rootReducers: {}、enhancers: []、middlewares: [],devtoolOptions注入 store 名),随后执行validateConfig()(validate.ts#L53-L83)——reducers必须是对象、middlewares/enhancers必须是数组、combineReducers/createStore若提供必须是函数,否则开发环境下抛出聚合错误(该校验仅在NODE_ENV !== 'production'时执行,见 validate.ts#L35)。redux.test.ts 与 L100-L109 分别验证了传入非法combineReducers(42)与非法createStore(42)会直接抛错。
  2. 插件合并:createConfig遍历插件,把plugin.config中的 models、redux.initialState、redux.reducers、enhancers、middlewares合并进用户配置,且用户配置在合并中始终优先(config.ts#L41-L82,其中combineReducers/createStore采用「已存在则不被插件覆盖」的策略,并有对应测试 createConfig.test.ts#L141-L177)。从源码结构看,有一处值得留意:合并插件rootReducers的语句实际读取的是plugin.config.redux.reducers字段(config.ts#L58-L61),如果你的插件依赖提供rootReducers,建议在本地跑一遍验证实际行为。
  3. 中间件注入:createRematchStore向reduxConfig.middlewares追加 effects 中间件与各插件中间件(rematchStore.ts#L30-L36)。
  4. 模型编译与根 reducer 组装:createReduxStore依次执行「模型 reducer 编译 →mergeReducers→ rootReducers 包裹 → 插件onRootReducer钩子 → compose →createStore」,即 reduxStore.ts#L18-L44 的全部流程。

与模型 baseReducer 的协作

config.redux并非孤立的逃生舱:模型侧的baseReducer与 Redux 生态动作的衔接同样发生在这一层。createModelReducer 中,若模型定义了baseReducer,action 会先经过它处理,再把结果传给模型自身的组合 reducer——这让旧式 Redux reducer 可以直接承载在模型上。redux.test.ts#L43-L87 用「effect dispatch 一个fromRedux类型 action →baseReducer消费 payload →store.getState().chicken.message更新」的完整用例验证了这条链路,是迁移纯 Redux 代码时值得参照的参考实现。

小结

config.redux是 Rematch 暴露的 Redux 层定制全集,九项配置各自对应源码中一个明确的可替换点:initialState透传给createStore,reducers与模型 reducer 共用合并表,middlewares/enhancers进入最终 compose 并自动追加 effects 与插件中间件,rootReducers以「先改写状态再进入正常 reducer 链」的方式提供全局钩子,combineReducers/createStore是整函数级替换,devtoolOptions在默认 store 名之上做浅合并,devtoolComposer则把 compose 环节整体交给远程 Devtools。所有配置项的非法值都会在内建校验中被拦下,并有 packages/core/test/redux.test.ts 与 packages/core/test/createConfig.test.ts 作为行为基准。对于绝大多数场景,优先使用模型与插件体系;只有在迁移旧 Redux 代码库、构建自研插件或接入特殊中间件/远程调试通道时,才需要深入这一层——而当你需要时,上述源码路径就是最权威的行为依据。

  • 前端

【免费下载链接】rematch

The Redux Framework

项目地址:https://gitcode.com/gh_mirrors/re/rematch
点击查看免费下载
上一篇:Telegraf dmcache 输入插件实战:基于 dmsetup 的 Linux Device Mapper 缓存监控指南
下一篇:KBEngine账号系统完全指南:从零构建MMOG游戏登录体系

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询