React Router Защищенные маршруты запускаются до получения токена пользователя - PullRequest
0 голосов
/ 10 мая 2018

У меня есть приложение 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, и при нажатии она правильно отображает список книг, когда пользователь вошел в систему.

Проблема возникает, когда я пытаюсь перейти по URL-адресу http://localhost:3000/books из браузера (т. Е. Не нажатием кнопки). Компонент ProtectedRoute, по-видимому, визуализируется до того, как fetchUser() вернет объект состояния 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 прямо из браузера, не нажимая кнопку.

1 Ответ

0 голосов
/ 10 мая 2018

Вызов асинхронного действия в componentWillMount не предотвратит его рендеринг, пока действие не будет завершено.

В вашем случае это ничем не отличается от выполнения в componentDidMount (и поэтому componentWillMount будет устаревшим в React 17).

You 'Я должен решить, что отображать пользователю до завершения fetchUser (что может занять несколько секунд при медленном соединении).
Возможно, счетчик?

...