Redux 存储在调度后不更新(异步数据加载)
Posted
技术标签:
【中文标题】Redux 存储在调度后不更新(异步数据加载)【英文标题】:Redux store not updating after dispatch (async data load) 【发布时间】:2021-09-05 00:57:10 【问题描述】:我遇到了一个奇怪的问题。我调用dispatch
方法从服务器加载一些数据。这很好用,我设法获取我的数据并更新减速器状态。但是 redux 存储状态似乎没有更新。 useSelector
常量永远不会更新。任何想法?感谢您的帮助!
这里是代码...
App.tsx
function App(): ReactElement
//* Init *//
const alertPopupRef = useRef(null);
const [dataLoaded, setDataLoaded] = useState<boolean>(false);
const applicationPreferences = useSelector<RootState, ApplicationPreferences>(state => state.applicationPreferences);
const dispatch = useDispatch();
useEffect(() =>
// This code is only triggered once, when the component is mounted.
console.log(applicationPreferences);
, [applicationPreferences]);
dispatch(loadApplicationPreferences(showError));
// Just for test.
setTimeout(() =>
// The 'ApplicationPreferences' variable is still empty.
console.log(store.getState());
, 3000);
//* Component Functions *//
function showError(err: ApiBusinessLayerError): void
alertPopupRef.current.show(AlertsTypes.Error, err.error, err.description, true);
console.log("showAlert is triggered.");
return (
dataLoaded ?
<AlertContext.Provider value= showError >
<Alert ref=alertPopupRef />
<Router>
<Switch>
<Route exact path="/" component=public_welcome_page />
<Route path="/signup" component=public_signup_page />
</Switch>
</Router>
</AlertContext.Provider>
:
<div style=styles.loading_page>
<Alert ref=alertPopupRef />
<div style=styles.loading_image_container>
<img src=loadingImage />
</div>
<div>
<img src=logo style=styles.logo />
</div>
<div>
Language: applicationPreferences.language
</div>
</div>
);
application_preferences_reducer.ts
import produce from "immer";
import ApiBusinessLayerError, ApiDataTypes, get from "../api_business_layer";
import ApplicationPreferences from "../models/application_preferences";
import RootState from "../store";
//* ┌──────────────────┐
//* │ ETI DECLARATIONS │
//* └──────────────────┘
export interface ApplicationPreferencesState
language: string;
server: string;
isInDevelopement: boolean;
export enum ApplicationPreferencesActionsTypes
SET_PREFERENCES = "SET_PREFERENCES"
export type ApplicationPreferencesAction =
type: ApplicationPreferencesActionsTypes,
payload: ApplicationPreferences[]
//* ┌─────────┐
//* │ ACTIONS │
//* └─────────┘
export function loadApplicationPreferences(errorCallback: (err: ApiBusinessLayerError) => void): Function
return async (dispatch: (action: ApplicationPreferencesAction) => RootState, getState: () => RootState): Promise<void> =>
get<ApplicationPreferences>(ApiDataTypes.ApplicationPreferences, null, null)
.then(data => dispatch( type: ApplicationPreferencesActionsTypes.SET_PREFERENCES, payload: data ); )
.catch((err: ApiBusinessLayerError) => errorCallback(err); );
//* ┌─────────┐
//* │ REDUCER │
//* └─────────┘
const initialState: ApplicationPreferencesState =
language: "",
server: "",
isInDevelopement: false
const routes: [actionType: string]: (state: ApplicationPreferencesState, action: ApplicationPreferencesAction) => ApplicationPreferencesState =
[ApplicationPreferencesActionsTypes.SET_PREFERENCES]: _setApplicationPreferences,
function applicationPreferencesReducer(state: ApplicationPreferencesState = initialState, action: ApplicationPreferencesAction): ApplicationPreferencesState
if (!routes[action.type]) return state;
return routes[action.type](state, action);
function _setApplicationPreferences(state: ApplicationPreferencesState, action: ApplicationPreferencesAction): ApplicationPreferencesState
return produce(state, state =>
// The state is correctly set here.
state = JSON.parse(JSON.stringify(action.payload[0]));
);
export default applicationPreferencesReducer;
store.ts
import applyMiddleware, CombinedState, combineReducers, createStore from "redux";
import thunk from "redux-thunk";
import applicationPreferencesReducer, ApplicationPreferencesState from "./reducers/application_preferences_reducer";
import languagesReducer, LanguagesState from "./reducers/languages_reducer";
import signInReducer, SignInState from "./reducers/signin_reducer";
import userPrivilegesReducer, UserPrivilegesState from "./reducers/user_privileges_reducer";
import userTypesReducer, UserTypesState from "./reducers/user_types_reducer";
export type RootState = CombinedState<
applicationPreferences: ApplicationPreferencesState;
language: LanguagesState;
signIn: SignInState;
userTypes: UserTypesState;
userPrivileges: UserPrivilegesState;
>
export const rootReducer = combineReducers(
applicationPreferences: applicationPreferencesReducer,
language: languagesReducer,
signIn: signInReducer,
userTypes: userTypesReducer,
userPrivileges: userPrivilegesReducer
);
const store = createStore(rootReducer, applyMiddleware(thunk));
export default store;
index.tsx
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import "bootstrap/dist/css/bootstrap.min.css";
import "bootstrap/dist/js/bootstrap.min.js";
import App from "./App";
import Provider from 'react-redux';
import store from "./data/store";
ReactDOM.render(
<Provider store=store>
<App />
</Provider>
, document.getElementById('root')
);
【问题讨论】:
你是在 index.js 中初始化存储吗?另外,你的应用组件周围有不确定为什么要在 reducer 中使用生产,因为您实际上并没有更改任何状态子集,而是返回一个全新创建的状态。我认为您可以执行以下操作:
//don't you hate code that wanders off the right side of the screen so you can't see what's going on, when someone sets their editor/formatter to a line length over 80
function _setApplicationPreferences(state: ApplicationPreferencesState, action: ApplicationPreferencesAction): ApplicationPreferencesState
return JSON.parse(JSON.stringify(action.payload[0]));
【讨论】:
太棒了!我现在在工作。我仍然不明白为什么,但它有效!非常感谢!以上是关于Redux 存储在调度后不更新(异步数据加载)的主要内容,如果未能解决你的问题,请参考以下文章
Next js 应用刷新时,useEffect 不调度 redux saga 动作并更新状态