如何在自定义NPM包的TS函数中访问Redux store实例
你代码里直接写<appsstore>.getState()是行不通的,store是消费端应用调用创建方法生成的局部变量,NPM包无法跨作用域直接拿到这个实例,以下是三种可落地的实现方式,按业务场景选择即可:
方案1:包初始化时手动传入store(通用度最高)
这是最通用的实现,不额外依赖React/React-Redux,全场景可用。
核心逻辑是在包内暴露一个初始化方法,让消费端创建完store之后主动把实例传进来,包内部缓存这个实例,校验函数直接调用缓存的实例即可。
NPM包代码修改
import { combineReducers } from 'redux'; import someNpmReducer from './some-reducer'; // 缓存传入的store实例 let cachedStore: any = null; /** * 初始化包依赖的store实例,需消费端在创建store后立即调用 */ export function initPackageStore(store: any) { cachedStore = store; } export function SomeCheck(testString: string): boolean { if (!cachedStore) { throw new Error('请先调用initPackageStore传入应用store实例,再执行校验逻辑'); } const rootState = cachedStore.getState(); // 按你配置的reducer挂载路径取包对应的state片段 const packageState = rootState.npmReducers?.npmgetReducer; // 这里写你的校验逻辑 return Boolean(packageState && packageState.targetValue === testString); } // 原有reducer导出保持不变 const npmReducers = combineReducers({ npmgetReducer: someNpmReducer }); export default npmReducers;
消费端代码修改
在创建完store的位置,调用初始化方法传入实例即可:
import { createStore, combineReducers } from 'redux'; import npmReducers, { initPackageStore } from '你的npm包名'; import appRed_1 from './reducers/app1'; import appRed_2 from './reducers/app2'; const applicationReducers = combineReducers({ npmReducers, applicationReducer_1: appRed_1, applicationReducer_2: appRed_2, }); const store = createStore(applicationReducers); // 传入store实例完成包初始化 initPackageStore(store); export default store; export type ApplicationRootState = ReturnType<typeof applicationReducers>;
方案优点:实现简单无黑魔法,兼容所有Redux使用场景,不管是在普通工具函数、React组件还是非React环境都能调用校验方法。
注意事项:必须保证initPackageStore在所有SomeCheck调用之前执行,否则会抛出初始化错误。
方案2:基于React-Redux上下文获取store(适合仅在组件内调用的场景)
如果你的校验函数只会在React组件、自定义Hook里调用,可以直接用React-Redux内置的useStore Hook拿实例,不需要手动初始化传参。
NPM包代码修改
import { useStore } from 'react-redux'; // 原有reducer、combineReducers逻辑保持不变 export function useSomeCheck(testString: string): boolean { const store = useStore(); const rootState = store.getState(); const packageState = rootState.npmReducers?.npmgetReducer; // 执行校验逻辑 return Boolean(packageState && packageState.targetValue === testString); }
消费端使用
组件内直接调用Hook即可:
import { useSomeCheck } from '你的npm包名'; export default function DemoComponent() { const checkPass = useSomeCheck('test-str'); return <div>校验结果:{String(checkPass)}</div>; }
方案优点:不需要手动传store做初始化,和React-Redux生态完全对齐,没有额外的接入成本。
限制:只能在被React-Redux的Provider包裹的React组件环境内使用,无法在普通JS/TS工具函数中调用。
方案3:直接传入待校验的state片段(耦合度最低)
如果不想让包和store实例产生任何耦合,可以直接把校验函数的入参改成接收包对应的state片段,完全不需要在包内感知store的存在。
NPM包代码修改
// 定义你包内reducer维护的state类型 interface NpmReducerState { targetValue: string; // 其他state字段 } export function SomeCheck(pkgState: NpmReducerState, testString: string): boolean { // 直接基于传入的state做校验 return pkgState.targetValue === testString; } // 原有reducer导出保持不变
消费端使用
调用时通过useSelector拿到对应的state片段传入即可:
import { useSelector } from 'react-redux'; import { SomeCheck } from '你的npm包名'; import type { ApplicationRootState } from './store'; export default function DemoComponent() { const pkgState = useSelector((state: ApplicationRootState) => state.npmReducers.npmgetReducer); const checkPass = SomeCheck(pkgState, 'test-str'); return <div>校验结果:{String(checkPass)}</div>; }
方案优点:包和Redux完全解耦,不需要维护store引用,单元测试时不需要mock整个store,直接传入测试state即可,可维护性最高。
注意事项:需要消费端自己从store里选出对应的state片段传入,调用方需要知道reducer的挂载路径。
内容的提问来源于stack exchange,提问作者fireholster

