分派动作后,React 无法使用更新的 Redux 状态

时间:2021-03-01 03:27:09

标签: javascript reactjs redux redux-thunk

我对 React 和 Redux 比较陌生,并通过我的个人项目学习它们。

这里的问题是 isAuthed 在执行 rest.dispatch(actions.isValidUser(json)) 后无法使用更新的 Redux 状态。据我所知,Redux 状态是由操作更新的。 (但我没有看到更新后调用了 connect()...我不知道这是否与此问题有关。)

我还尝试在我的操作文件中使用 Redux-thunk 从 API 端点获取数据并使用 useEffect(),但它没有解决问题。你能帮我吗?

提前致谢。

**ProtedtedRoute.jsx**

import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import * as actions from '../actions/actions';


function ProtectedRoute({ component: Component, isAuthed, ...rest }) {
  
  async function verifyUser() {
     // checking if a user is valid by checking JWT
      const res = await fetch(ENDPOINT, reqOptions);
    if (res.status === 200) {
      const json = await res.json();
      rest.dispatch(actions.isValidUser(json));
    } else {
      // failure handling
    };
  };

  verifyUser();

  return (
    <Route
      {...rest}
      render={(props) => isAuthed == true ? <Component {...props} /> : <Redirect to={{ pathname: '/login', state: { from: props.location } }} />}
    />
  );
};


export default connect(state => {
  return {
    isAuthed: state.isAuthenticated
  }
})(ProtectedRoute);

**reducer.js**
const initState = {
    data: {},
    // when a user is valid, it will be ```true```
    isAuthenticated: false
}


**App.js**

function App() {

  return (
    <Provider store={store}>
        <BrowserRouter>
          <div>
            <div className="content">
              <Switch>
                <Route exact path="/" component={Home} />
                <PublicRoute path="/login" component={LogIn} />
                <PublicRoute path="/signup" component={SignUp} />
                <ProtectedRoute path="/dashboard" component={Dashboard} />
              </Switch>
              ...


**Login.jsx**

 const res = await fetch(ENDPOINT, { reqOptions});
        if (res.status === 200) {
            props.history.push('/dashboard');
        else{
            // error handling
        }

1 个答案:

答案 0 :(得分:0)

您不希望像 verifyUser(); 这样的函数调用只是漂浮在组件中。它需要位于 useEffect 钩子内。

您的 Login 组件会在您重定向到 Dashboard 之前获取端点,因此您无需再次获取端点即可访问 Dashboard通过PrivateRoute

您可以更改您的 initialState 以包含 isAuthenticated: undefined,如“我们不知道它们是否通过身份验证,因为我们还没有检查过。”

那么在PrivateRoute中,我们只需要在verifyUser的值为isAuthed时调用undefined,这意味着我们还没有检查。如果是 truefalse,我们只使用现有值。

我们的 aysnc 流程仍然存在一些问题,因为我们不想在 Redirect 完成之前 PrivateRoute 离开 verifyUser。为此,我们可以有条件地呈现在等待凭据时显示的加载状态。

我不知道这是最优雅的解决方案,但它应该有效

function ProtectedRoute({ component: Component, isAuthed, ...rest }) {

  async function verifyUser() {
    // checking if a user is valid by checking JWT
    const res = await fetch(ENDPOINT, reqOptions);
    if (res.status === 200) {
      const json = await res.json();
      rest.dispatch(actions.isValidUser(json));
    } else {
      // failure handling
    }
  }

  useEffect(() => {
    if (isAuthed === undefined) {
      verifyUser();
    }
  }, [isAuthed]); //re-run when isAuthed changes

  return (
    <Route
      {...rest}
      render={(props) =>
        isAuthed === undefined ? (
          <Loading />
        ) : isAuthed === true ? (
          <Component {...props} />
        ) : (
          <Redirect
            to={{ pathname: "/login", state: { from: props.location } }}
          />
        )
      }
    />
  );
}