如何解决循环依赖 how-to-fix-circular-dependency
在写 redux 项目时,本人遇到了 循环依赖导致的 引入xxx变量时为undefined 的问题。
原文:JS modules can have "circular reference" problems if two modules try to import each other.
首先要明白:
循环依赖本身 对于ES6模块化 不是问题(只是可能造成问题)
问题在于:循环依赖之后,我们使用某些变量或方法时,这些变量或方法 是否已准备就绪!?
问题情景还原
这是 App.tsx
import { Provider } from "react-redux";
import { BrowserRouter, Route, Routes } from "react-router-dom";
// 先引入了Home组件
import Home from "./pages/Home";
// 最后引入 store
import store from "./store";
function App() {
return (
<Provider store={store}>
<BrowserRouter>
<div className="app">
<Routes>
<Route element={<Home />}></Route>
</Routes>
</div>
</BrowserRouter>
</Provider>
);
}
export default App;
在 Home 组件 中,需引入某 AsyncThunk,该AsyncThunk 又需要引入 request.ts,request.ts 中又需要引入 store, store 中需要引入 rootReducer,rootReducer 需要引入Home组件中引入的AsyncThunk。
如图,一个依赖循环出现。但是
es6模块化其实解决了循环依赖,所以这没有问题。
问题在于: 在这种条件下,Home组件要使用 XXXAyncThunk时,模块加载机制会认为:后面加载 store 时,才会初始化 XXXAyncThunk,现在 store 在 Home 加载后才会加载,现在想在Home使用 XXXAyncThunk,所以报错:
Uncaught ReferenceError: Cannot access 'getUserChannel' before initialization
最终 解决方式:
上移 import store from "./store"; 引入 store 位置
// 先引入 store
import store from "./store";
import { Provider } from "react-redux";
import { BrowserRouter, Route, Routes } from "react-router-dom";
// 后引入 Home组件
import Home from "./pages/Home";
function App() {
return (
<Provider store={store}>
<BrowserRouter>
<div className="app">
<Routes>
<Route element={<Home />}></Route>
</Routes>
</div>
</BrowserRouter>
</Provider>
);
}
export default App;
没有报错了,使用正常。
原因:
这样调整 Import 顺序后,相当于:不论如何,先把这个 循环依赖链条 上相关的东西 都加载好了
这个循环依赖问题已经。
之后,组件内使用该 循环依赖链条 上的任何东西,都是已经加载好的,就不会报错了。
总结:
在 ES6 模块下(据说 CommnJS 还有不一样的问题),解决 循环依赖 产生问题的思路就是:
- 先将 循环依赖链 加载好
- 再加载 需使用该依赖链中内容的 其它模块
不要让 其它模块,从某一环切入依赖循环,进而才加载该依赖循环
其它解决方案:
提供两个文档,提供了很好的循环依赖 circular-dependency 的解决思路
其实本质道理,和上述我的方式差不多,先把所有东西集中到一个位置,一起全部导出。
也就是我们可能见过的这样的 index.js 文件
export * from "./x"
export * from "./xx"
export * from "./xxx"