【发布时间】:2021-01-18 02:28:38
【问题描述】:
我目前正在使用 Redux、Redux Thunk 和 NextJS,并试图弄清楚如何在功能组件的函数中访问更新后的 redux 状态。
正如您在下面的代码中看到的那样,在 handleSubmit 函数中,我想更新 redux 状态,然后检查状态值并决定应该将用户带到哪个路由。
以前在我的旧项目中,使用 mapStateToProps 和 Class 组件,我能够在 handleSubmit 函数中访问更新后的 redux 状态,但是当使用功能组件时,两个选项(useSelector hook 或 mapStateToProps connect()) 似乎不起作用。
起初我以为组件没有重新渲染,但是当检查 useEffect() 中的状态时,我可以看到状态正在更新,并且组件能够查看更新的值。
是否有我明显遗漏的东西,或者功能组件无法实现这种方式?
loginPage.tsx
import LoginForm, { FormData } from 'components/Forms/LoginForm';
import Layout from 'components/Layout';
import { FORM_ERROR } from 'final-form';
import StatusCodes from 'lib/enums/statusCodes';
import { storeAuthToken } from 'lib/helpers/auth';
import { useRouter } from 'next/router';
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { ApplicationState } from 'redux/store';
const LoginPage = () => {
const router = useRouter();
const dispatch = useDispatch();
const { auth } = useSelector((state: ApplicationState) => ({ auth: state.auth }));
const handleSubmit = async (values: FormData) => {
if (values && values.username && values.password) {
try {
// Updates redux store
await storeAuthToken(dispatch, values.username, values.password);
} catch (error) {
if (error === StatusCodes.BadRequest) {
return { [FORM_ERROR]: 'Sorry, you have entered incorrect details. Please try again' };
} else {
return { [FORM_ERROR]: 'Sorry, there was an issue trying to log you in' };
}
}
// Can't see updated values
console.log('Auth: ', auth);
if (auth.parsedJwt && auth.parsedJwt.changePassword) {
router.push({ pathname: '/update-password' });
return;
}
router.push('/dashboard');
}
};
useEffect(() => {
// Can see the updated values
console.log('New Auth: ', auth);
}, [auth]);
return (
<Layout hideProfileMenu title="Login">
<LoginForm onSubmit={handleSubmit} />
</Layout>
);
};
export default LoginPage;
我已经附加了 store 和 reducer,以防我设置错误。
store.tsx
import Auth from 'lib/interfaces/auth';
import { Context, createWrapper, HYDRATE, MakeStore } from 'next-redux-wrapper';
import { AnyAction, applyMiddleware, CombinedState, combineReducers, createStore, Dispatch, Reducer } from 'redux';
import thunkMiddleware, { ThunkAction, ThunkDispatch, ThunkMiddleware } from 'redux-thunk';
import authReducer from './auth/reducer';
export interface ApplicationState {
auth: Auth
}
const isDebug = process.env.NODE_ENV !== 'production';
const bindMiddleware = (middleware: ThunkMiddleware) => {
if (isDebug) {
const { composeWithDevTools } = require('redux-devtools-extension');
return composeWithDevTools(applyMiddleware(middleware));
}
return applyMiddleware(middleware);
};
const combinedReducer: Reducer<ApplicationState> = combineReducers<ApplicationState>({
auth: authReducer
});
const reducer = (state: ApplicationState, action: AnyAction) => {
if (action.type === HYDRATE) {
const nextState: CombinedState<ApplicationState> = {
...state,
...action.payload
};
return nextState;
} else {
return combinedReducer(state, action);
}
};
const makeStore: MakeStore<ApplicationState> = (_context: Context) => createStore(reducer as Reducer<ApplicationState, AnyAction>, bindMiddleware(thunkMiddleware));
export const wrapper = createWrapper<ApplicationState>(makeStore, { debug: isDebug });
reducer.tsx
import Auth from 'lib/interfaces/auth';
import { Reducer } from 'redux';
import { ActionTypes, AuthAction } from './actions';
const reducer: Reducer<Auth, AuthAction> = (state: Auth = {} as Auth, action: AuthAction): Auth => {
switch (action.type) {
case ActionTypes.UpdateToken:
return Object.assign({}, state, { token: action.token });
case ActionTypes.UpdateRefreshToken:
return Object.assign({}, state, { refreshToken: action.refreshToken });
case ActionTypes.UpdateParsedJwt:
return Object.assign({}, state, { parsedJwt: action.parsedJwt });
case ActionTypes.UpdateUuid:
return Object.assign({}, state, { uuid: action.uuid });
default:
return state;
}
};
export default reducer;
【问题讨论】:
-
redux 调度程序异步运行,因此 handleSubmit 可能会在更新 auth 值之前完成。由于此函数还向路由器推送了一条新路径,我假设这将卸载登录组件,因此下面的 useEffect 将不再触发。如果删除 router.push 调用,useEffect 是否会使用新的 auth 值触发?
-
或者,您可以让 storeAuthToken 函数返回 auth 值,以专门用于 handleSubmit 函数以及调度它。
-
@andyd_28 当我删除 router.push 调用时,useEffect 仍会以新的身份验证值触发。
标签: javascript reactjs redux react-redux redux-thunk