【发布时间】:2022-02-26 07:05:38
【问题描述】:
我正在重构使用 NextJS 和 redux 编写的现有 react-leaflet 应用程序。我正在引入 redux-sagas 来清理 api 调用逻辑。在某些 sagas 中,我想使用一些传单地理功能:
function* handleGeocode(): Generator {
if (window) {
try {
const response = yield call(axios.get, `nominatim-url-blah-blah`);
const { lat, lon: lng } = response[0];
const bounds = L.latLngBounds([ // Use leaflet function here
[lat - 0.5, lng - 0.5],
[lat + 0.5, lng + 0.5],
]);
yield put(
ActionCreators.requestDataInBounds(bounds))
);
} catch (e) { }
}
}
function* watchHandleGeocode() {
yield takeEvery(ActionTypes.REQ_GEOCODE, handleGeocode);
}
function* searchSagas() {
yield all([fork(watchHandleGeocode),
}
L.latLngBounds 的使用运行了一些传单代码,这些代码在深处最终需要访问窗口对象。
我收到错误ReferenceError: window is not defined。
我知道这一直是 react-leaflet 的问题。我已经阅读了Leaflet with next.js 的问题,但这不是我的问题。我的实际地图组件已经使用动态导入:
const Map = dynamic(() => import("../components/Map"), {
ssr: false,
});
我对此没有意见。一旦我将传单本机代码引入 sagas,我的问题就出现了。一旦使用 saga 中间件,就好像所有 sagas 都在运行:
const sagaMiddleware = createSagaMiddleware();
function initStore(preloadedState) {
const store = createStore(
rootReducer,
preloadedState,
composeWithDevTools(applyMiddleware(sagaMiddleware))
);
return store;
}
export const initializeStore = (preloadedState = {}) => {
let _store = store ?? initStore(preloadedState);
// After navigating to a page with an initial Redux state, merge that state
// with the current state in the store, and create a new store
if (preloadedState && store) {
_store = initStore({
...store.getState(),
...preloadedState,
});
// Reset the current store
store = undefined;
}
// For SSG and SSR always create a new store
if (typeof window === "undefined") return _store;
if (typeof window !== "undefined") {
sagaMiddleware.run(rootSaga);
}
// Create the store once in the client
if (!store) store = _store;
return _store;
};
export function useStore(initialState) {
const store = useMemo(() => initializeStore(initialState), [initialState]);
return store;
}
因此,尽管我只运行 sagaMiddleware if window !== "undefined",并且 saga 本身被包裹在 if (window) 语句中,但我仍然收到此错误。就好像代码正在运行并运行 L.latLngBounds 函数,即使调用 handleGeocode saga 的操作当前甚至没有在代码中的任何地方被调用!一旦我删除对 L.latLngBounds 的调用,错误就会消失。
这里出了什么问题?如果运行这个 saga 的操作甚至没有被调用,NextJS 是如何运行这段代码甚至出现这种类型的错误的?如何重新连接我的 saga,以便可以在其中使用本机传单函数?
【问题讨论】:
-
如果我理解正确,您的
handleGeocode函数与您的Map组件完全分开。它还导入 Leaflet,但您尝试通过检查window来保护其仅用于客户端。但它是如何导入的呢? -
也许尽量避免在 sagas 中使用传单代码并仅调度 lat lng 或从异步调用接收的任何其他数据。然后在您想要使用它们的组件内部,使用传单代码使用从 redux 接收的 lat lng 形成边界。
-
@kboul 我正在考虑这样做,我可能不得不这样做。但是能够在 saga 中包含一些处理逻辑,利用 Leaflet 的强大地理功能,将非常有用。我想我不明白为什么在此代码发送到客户端之前尝试访问窗口
-
@ghybs,它不会在任何地方导入。我们使用 saga 中间件
applyMiddleware(sagaMiddleware)和运行该中间件sagaMiddleware.run(rootSaga)将所有 redux sagas 链接到商店,其中 rootSaga 基本上包含应用程序中的所有 sagas。其中一个传奇是watchHandleGeocode,它监听ActionTypes.REQ_GEOCODE从应用程序的任何地方被触发。 Sagas 监听它,然后在handleGeocode中运行代码。我不明白的是为什么 L.latLngBounds 在 compilation 时被调用,而不是仅在动作触发时调用 -
@SethLutske 它可能不是javascript错误,而是打字稿错误吗?这意味着代码实际上并没有运行,它只是编译期间的 TS 静态分析?
标签: reactjs next.js leaflet redux-saga react-leaflet