React 18.2.0中Redux异步预加载状态配置问题及顶层await咨询
问题解答
1. React 18.2.0是否支持顶层await?
React 18.2.0本身不限制顶层await的使用——顶层await是ES模块(ESM)的标准特性,和React版本没有直接关联。能不能用顶层await,取决于你的项目打包工具(比如你用的Webpack)是否配置为支持ES模块,并且开启了顶层await功能。你现在遇到的Webpack配置问题,是打包工具层面的限制,不是React的问题。
2. 异步获取preloadedState的替代方案
直接把异步函数传给preloadedState不行,因为它需要的是同步的初始状态值,而不是Promise。这里有几个可行的替代方案:
方案一:在应用启动前先获取数据,再初始化store和渲染App
修改你的入口文件(比如index.js),先异步获取初始状态,再创建store并渲染React应用:
import React from 'react'; import ReactDOM from 'react-dom/client'; import { Provider } from 'react-redux'; import { configureStore } from '@reduxjs/toolkit'; import App from './App'; import { selectionStateSliceReducer, externalTimingsReducer } from './reducers'; async function initApp() { // 先获取异步数据 const selectionState = await window.browser.storage.local.get("selectionState"); const externalTimings = await window.browser.storage.local.get("externalTimings"); // 用获取到的数据创建store const store = configureStore({ preloadedState: { selectionState, externalTimings }, reducer: { selectionState: selectionStateSliceReducer, externalTimings: externalTimingsReducer, }, }); // 渲染应用 const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.StrictMode> <Provider store={store}> <App /> </Provider> </React.StrictMode> ); } initApp();
方案二:先创建空store,再通过dispatch初始化状态
先创建不带preloadedState的store,之后在入口文件或者根组件里,异步获取数据后dispatch对应的初始化action:
// store.js export const store = configureStore({ reducer: { selectionState: selectionStateSliceReducer, externalTimings: externalTimingsReducer, }, }); // 示例:在selectionStateSlice中定义初始化action // import { createAction, createReducer } from '@reduxjs/toolkit'; // export const initSelectionState = createAction('selectionState/init'); // export const selectionStateSliceReducer = createReducer({}, (builder) => { // builder.addCase(initSelectionState, (state, action) => { // return action.payload; // }); // });
然后在入口文件或者根组件中:
import { store } from './store'; import { initSelectionState, initExternalTimings } from './slices'; async function loadInitialState() { const selectionState = await window.browser.storage.local.get("selectionState"); const externalTimings = await window.browser.storage.local.get("externalTimings"); store.dispatch(initSelectionState(selectionState)); store.dispatch(initExternalTimings(externalTimings)); } // 启动应用时调用 loadInitialState();
方案三:在根组件中用useEffect加载初始状态
如果不想阻塞应用渲染,可以先渲染应用,然后在根组件的useEffect里异步获取数据并更新store:
import { useEffect } from 'react'; import { useDispatch } from 'react-redux'; import { initSelectionState, initExternalTimings } from './slices'; function App() { const dispatch = useDispatch(); useEffect(() => { async function loadState() { const selectionState = await window.browser.storage.local.get("selectionState"); const externalTimings = await window.browser.storage.local.get("externalTimings"); dispatch(initSelectionState(selectionState)); dispatch(initExternalTimings(externalTimings)); } loadState(); }, [dispatch]); return <div>你的应用内容</div>; }
这种方式的好处是不会阻塞应用渲染,用户能先看到加载状态或者默认UI,等数据获取完成后再更新页面。
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

