React Router Protected Routes 在获取用户令牌之前触发

React Router Protected Routes firing before getting user token

我有一个 React 应用程序,它会在 componentWillMount() 上触发动作创建者从存储的令牌中获取当前用户:

App.js

...
  async componentWillMount() {
    const token = localStorage.getItem("token");
    if (token) {
      await this.props.fetchUser();
    }
  }
...

然后,在同一个 App.js 文件中,我定义了一些路由。为简单起见,我将显示两条路线:

App.js

...
render() {
    return (
      <Router>
        <div>
          <Reboot />
          <Route component={Header} />
          <Route exact path="/" component={Landing} />
          <ProtectedRoute
            isSignedIn={this.props.authenticated.jwtToken}
            path="/books"
            component={BookList}
          />
        </div>
      </Router>
    );
  }
...

Header 组件中,我有一个重定向到 /books 的按钮,点击后会在用户登录时正确显示图书列表。

当我尝试从浏览器直接转到 http://localhost:3000/books URL 时出现问题(即不是通过单击按钮)。 ProtectedRoute 组件似乎在 fetchUser() returns authenticated 状态对象之前呈现,因此将重定向回主登录页面。

这是 ProtectedRoute 组件:

export const ProtectedRoute = ({
  component: Component,
  jwtToken,
  isSignedIn,
  ...rest
}) => {
  return (
    <Route
      {...rest}
      render={props =>
        isSignedIn ? (
          <Component {...props} />
        ) : (
          <Redirect
            to={{
              pathname: "/",
              state: { from: props.location, message: "You need to sign in" }
            }}
          />
        )
      }
    />
  );
}; 

这是 fetchUser() 的动作创建器:

export const fetchUser = () => async dispatch => {
  await dispatch({ type: FETCHING_USER });
  try {
    const res = await axios.get(`${API_URL}/api/current_user`, {
      headers: { authorization: localStorage.getItem("token") }
    });
    await dispatch({ type: FETCH_USER, payload: res.data });
  } catch (err) {
    // dispatch error action types
  }
};

我认为通过使用 async/await 语法,我可以维护已调度操作的顺序...

有人可以告诉我我做错了什么吗?理想情况下,我可以直接从浏览器到达 /books 路线,而无需单击按钮。

componentWillMount 中调用异步操作不会阻止它在操作完成之前呈现。

在你的情况下,这与在 componentDidMount 中执行没有什么不同(这也是为什么 componentWillMount 在 React 17 中将是 deprecated)。

您必须在 fetchUser 完成之前决定向用户显示什么(在慢速连接上可能需要几秒钟)。
也许是旋转器?