简体   繁体   中英

Function not receiving updated redux state even on re-render

I'm currently using Redux, Redux Thunk with NextJS and been trying to figure out how to access the updated redux state inside a function of a functional component.

As you can see in my code below, in the handleSubmit function, I want to update the redux state and then check the state value and decided which route it should take the user to.

Previously in my old project, using mapStateToProps with a Class component, I was able to access the updated redux state inside my handleSubmit function however when using a functional component both options ( useSelector hook or mapStateToProps with connect() ) doesn't seem to work.

At first I thought the component wasn't re-rendering however when checking the state in useEffect() , I can see that the state is getting updated and the component is able to view the updated values.

Is there something I'm clearly missing or is this way not possible with functional components?

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;

I've attached the store and reducer incase I've set it up wrong.

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;

I think the simplest solution is to return the auth object from 'storeAuthToken' as it keeps the error handling and result in the same logical flow, and it fixes the asynchronous issue identified in the comments.

 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 } from 'react-redux'; import { ApplicationState } from 'redux/store'; const LoginPage = () => { const router = useRouter(); const dispatch = useDispatch(); const handleSubmit = async (values: FormData) => { if (values && values.username && values.password) { try { // Updates redux store const authResult = await storeAuthToken(dispatch, values.username, values.password); if (authResult.parsedJwt && authResult.parsedJwt.changePassword) { router.push({ pathname: '/update-password' }); return; } } 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' }; } } router.push('/dashboard'); } }; return ( <Layout hideProfileMenu title="Login"> <LoginForm onSubmit={handleSubmit} /> </Layout> ); }; export default LoginPage;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM