为啥 redux 状态不能正确渲染?

Posted

技术标签:

【中文标题】为啥 redux 状态不能正确渲染?【英文标题】:Why redux state is not render correctly?为什么 redux 状态不能正确渲染? 【发布时间】:2021-08-06 15:07:48 【问题描述】:

您好,我在用户正确登录后尝试将用户推送到仪表板时遇到了一个问题,但没有成功,下面是代码:

LoginForm.js

const  isLoading, isAuth, error, message  = useSelector(
(state) => state.login
);
const handleSubmit = (e) => 
e.preventDefault();
console.log(values);//values=email:'..', pass:'..'
if (formValidation()) 
  dispatch(NewUserLogin(values)); 
  console.log(isAuth); //print false but in redux state print true
  if (isAuth) history.push('/dashboard');
 
;

LoginAction.js

export const NewUserLogin = (formValues) => async (dispatch) => 
try 
 dispatch(loginPending());
 const  status, message  = await LoginAPIRequest(formValues);

 if (status === 'success') 
  dispatch(loginSuccess(message));
  else 
  dispatch(loginFailure(message));
 
 console.log(status);
 console.log(message);
 catch (error) 
  dispatch(loginFailure(error.message));
 
;

loginSlice.js

import  createSlice  from '@reduxjs/toolkit';
const initialState = 
isLoading: false,
isAuth: false,
error: '',
;
const loginSlice = createSlice(
 name: 'Login',
 initialState,
 reducers: 
  loginPending: (state) => 
  state.isLoading = true;
  ,
  loginSuccess: (state,  payload ) => 
   state.isLoading = false;
   state.isAuth = true;
   state.message = payload;
   state.error = '';
  ,
  loginFailure: (state,  payload ) => 
  //actions.payload or shortcut payload
   state.isLoading = false;
   state.error = payload;
  ,
 ,
);

const  reducer, actions  = loginSlice;
export const  loginPending, loginSuccess, loginFailure  = actions;
export default reducer;

userAPI.js

import  createEndpointsAPI, ENDPOINTS  from './index';

export const LoginAPIRequest = (formValues) => 
  return new Promise(async (resolve, reject) => 
  //call api
  try 
    await createEndpointsAPI(ENDPOINTS.LOGIN)
      .create(formValues)
      .then((res) => 
        resolve(res.data);
        if (res.data.status === 'success') 
          resolve(res.data);
          sessionStorage.setItem('accessJWT', res.data.accessJWT);
          localStorage.setItem('sms', JSON.stringify(res.data.refreshJWT));
        
       console.log(res.data);
      )
     .catch((err) => 
       reject(err);
     );
   catch (error) 
    console.log(error);
    reject(error);
  
 );
;

index.js(根 API)

import axios from 'axios';

export const ENDPOINTS = 
  LOGIN: 'user/login',
  LOGOUT: 'user/logout',
  REGISTER: 'user/register',
;

const baseURL = 'http://localhost:3040/v2/';
export const createEndpointsAPI = (endpoint) => 
  let url = baseURL + endpoint + '/';
  return 
   fetchAll: () => axios.get(url),
   fetchById: (id) => axios.get(url + id),
   create: (newData) => axios.post(url, newData),
   update: (updateData, id) => axios.put(url + id, updateData),
   delete: (id) => axios.delete(url + id),
 ;
;

App.js

<MuiThemeProvider theme=theme>
  <CssBaseline />
  <Router>
    <Switch>
      <Route path='/' exact>
        <Login />
      </Route>
      <PrivateRoute path='/dashboard'>
        <Dashboard />
      </PrivateRoute>
      <Route path='*' component=() => '404 NOT FOUND' />
    </Switch>
  </Router>
</MuiThemeProvider>

PrivateRoute.js

 import  useSelector  from 'react-redux';

 const PrivateRoute = ( component: Component, ...rest ) => 
 const  isAuth  = useSelector((state) => state.login);
 console.log(isAuth);
 return (
  <Route
   ...rest
   render=(props) => 
     isAuth ? (
       <Component ...props />
     ) : (
       <Redirect
         to=
           pathname: '/',
           state:  from: props.location ,
         
       />
      );
      
     />
    );
   ;

  export default PrivateRoute;

问题是,isAuth 是一个 redux 状态,当用户正确登录时它应该返回 true,但它不是,我 console.log(isAuth) 第一次打印 false 即使用户正确登录,如果我再次单击登录,它在控制台日志中打印为 true 并将用户重定向到仪表板页面。 不知道为什么isAuth在使用正确登录的时候第一次返回false?请大家帮忙检查一下上面的代码,我都给你了。

【问题讨论】:

console.log('Log In)NewUserLogin函数中,实际上返回isAuth为false然后登录了,怎么办? 【参考方案1】:

日志:console.log(isAuth); 记录了stale closure,您可以尝试对 isAuth 施加影响,并在其为真时重定向。

这是一个例子:

const Component = (propps) => 
  const  isLoading, isAuth, error, message  = useSelector(
    (state) => state.login
  );
  const handleSubmit = (e) => 
    //...dispatches but doesn't check isAuth
  ;
  useEffect(() => 
    //go to dashboard if isAuth is true
    if (isAuth) history.push('/dashboard');
  , [isAuth]);//run effect when isAuth changes
;

【讨论】:

你能给我举个例子来说明如何避免过时的关闭吗?如何在 isAuth 上渲染效果? @Jonh 添加示例 我通过使用useEffect 应用您的想法并添加依赖项[isAuth],它正在工作,但它在useEffect(()=&gt;,[isAuth]) React Hook has a missing dependency: 'history' 内的虚拟工作室代码中显示警告 PrivateRoute.js我也用isAuthredux state,它返回false,我是否也需要在PrivateRoute.js中使用useEffect 我不知道我的PrivateRoute.js到底发出了什么,即使我从localStorage &amp; session中清除了Token,我仍然可以访问localhost:3001/dashboard,没有restriction完全没有

以上是关于为啥 redux 状态不能正确渲染?的主要内容,如果未能解决你的问题,请参考以下文章

ReactJS表单应用程序:如何阻止父组件重新渲染? /使用redux共享状态的正确方法

Redux 状态发生了变化,为啥不触发重新渲染? (Redux 传奇)

在 Redux thunk 中创建的数组未正确传递到状态树

我的 Redux 状态发生了变化,为啥 React 没有触发重新渲染?

react+redux 中预加载组件数据的正确方法

React Redux Store 更新,但组件不重新渲染