如何在React的public文件夹脚本中调用Redux dispatch
解决方案
方案1:将Redux Store挂载到全局window对象
在src目录的store创建文件里,把store实例挂载到window上,让public目录的脚本能直接访问dispatch方法:
// src/store.js import { configureStore } from '@reduxjs/toolkit'; import rootReducer from './reducers'; export const store = configureStore({ reducer: rootReducer, }); // 仅在开发环境或明确需要时挂载,避免生产环境暴露不必要的全局变量 if (process.env.NODE_ENV !== 'production') { window.store = store; }
之后在public目录的脚本里直接调用:
// public/custom-script.js // 假设要触发的action是updateData window.store.dispatch({ type: 'data/update', payload: { /* 从public脚本拿到的结果 */ } });
注意:如果用Redux Toolkit的createSlice,建议提前导出action creators并挂载到window,或者直接指定type和payload。生产环境若需挂载,建议用更隐蔽的全局变量名避免冲突。
方案2:通过自定义事件(CustomEvent)实现跨脚本通信
这种方式无需暴露全局store,耦合度更低,更贴合React设计模式:
- 在public脚本中触发自定义事件,携带需要传递的数据:
// public/custom-script.js // 假设已拿到要传给store的结果data const updateEvent = new CustomEvent('storeUpdate', { detail: { payload: data, actionType: 'data/update' } }); window.dispatchEvent(updateEvent);
- 在src的根组件(比如App.jsx)中监听事件,收到后调用dispatch:
// src/App.jsx import { useEffect } from 'react'; import { useDispatch } from 'react-redux'; import { updateData } from './features/dataSlice'; // RTK的action creator function App() { const dispatch = useDispatch(); useEffect(() => { const handleStoreUpdate = (e) => { dispatch(updateData(e.detail.payload)); // 也可以直接使用actionType:dispatch({ type: e.detail.actionType, payload: e.detail.payload }); }; window.addEventListener('storeUpdate', handleStoreUpdate); return () => window.removeEventListener('storeUpdate', handleStoreUpdate); }, [dispatch]); return ( {/* 应用组件内容 */} ); } export default App;
方案3:将public脚本逻辑迁移到src中
如果public脚本的功能可以在src内部实现,推荐这种方式,避免跨目录依赖问题:
比如加载第三方脚本并获取结果的场景,可以在src中动态加载脚本,回调中直接调用dispatch:
// src/components/ThirdPartyLoader.jsx import { useEffect } from 'react'; import { useDispatch } from 'react-redux'; import { updateData } from './features/dataSlice'; function ThirdPartyLoader() { const dispatch = useDispatch(); useEffect(() => { const script = document.createElement('script'); script.src = '/custom-script.js'; // public目录下的脚本路径 script.onload = () => { // 假设脚本加载后暴露全局方法getScriptResult window.getScriptResult((result) => { dispatch(updateData(result)); }); }; document.body.appendChild(script); return () => { document.body.removeChild(script); delete window.getScriptResult; // 清理全局方法 }; }, [dispatch]); return null; // 无需渲染内容 } export default ThirdPartyLoader;
在App组件中引入这个Loader组件即可。
内容的提问来源于stack exchange,提问作者Abenezer Bayeh
相关产品推荐
相关产品推荐

