Каковы последствия выполнения кода на следующей строке после хуков setState?

#reactjs #react-hooks

#reactjs #реагирующие перехваты

Вопрос:

Заранее прошу прощения за то, что задал вопрос, который обсуждался очень часто. Мой вопрос не о том, как правильно написать код, а о том, каковы последствия для выполнения этого не рекомендуется. Я не уверен, приемлемо ли выполнять код сразу после установки состояния в функциональных компонентах. React, похоже, отлично выполняет код без жалоб, однако каждое сообщение, которое я видел, предлагает написать последующий код в useEffect .

Пожалуйста, взгляните на этот фрагмент: LoginPage.jsx

 async function handleSubmit(e) {
  e.preventDefault();
  const user = await login({ username, password });
  setUser(user);

  // Why is this not recommended?
  history.push('/profile');
}
 

user состояние принадлежит компоненту верхнего уровня App , и оно должно быть определено для ProfilePage рендеринга без сбоев. user изначально undefined .

В этом конкретном сценарии user состояние будет обновлено, а затем браузер перенаправит на /profile без каких-либо видимых проблем. Похоже, это происходит синхронно, поскольку ProfilePage рендерится без сбоев.

контекст

 function App() {
  const [user, setUser] = useState(undefined);

  return (
    <Switch>
      <Route path='/login'>
        <LoginPage setUser={setUser} />
      </Route>
      <Route path='/profile'>
        <ProfilePage user={user} />
      </Route>
    </Switch>
  );
}
 
 function ProfilePage({ user }) {
  return <div>{user.username}</div>
}
 
 function LoginPage({ setUser }) {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');

  const history = useHistory();

  function handleChangeUsername(e) {
    setUsername(e.target.value);
  }

  function handleChangePassword(e) {
    setPassword(e.target.value);
  }

  async function handleSubmit(e) {
    e.preventDefault();
    const user = await login({ username, password });
    setUser(user);
    history.push('/profile');
  }

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" placeholder="username" value={username} onChange={handleChangeUsername} />
      <input type="text" placeholder="password" value={password} onChange={handleChangePassword} />
      <input type="submit" />
    </form>
  );
}
 

Ответ №1:

Это не рекомендуется, потому useState что перехват обновляет состояние асинхронно, и вы не можете зависеть от обновления состояния до перехода от компонента. Если у вас больше ничего не происходит в компоненте, и браузеру не нужно ждать ввода-вывода, тогда вы можете никогда не увидеть проблему. Однако позже это может сбить вас с толку, и вам потребуется целая вечность, чтобы понять это, потому что до этого момента это никогда не было проблемой.

Лучше всего следовать рекомендациям с useEffect помощью перехвата.