Заставьте useEffect hook запускаться перед рендерингом компонента

#javascript #reactjs #redux #react-redux #react-hooks

#javascript #reactjs #redux #реагировать-redux #реагирующие крючки

Вопрос:

У меня есть хук useEffect, который я использую в своем App.js досье. Он помещает данные в хранилище redux, которые мне нужно использовать в моем приложении. Но он рендерится до запуска useEffect, поэтому данные не определены. Затем useEffect выполняется правильно. Мне нужно, чтобы useEffect запускался до того, как что-либо будет отображено. Как я мог это сделать? Или какое другое решение я должен использовать? Я попытался полностью удалить useEffect и просто запустить действие, но это приводит к тому, что оно выполняется бесконечно. Это мой код:

 function App() {
  const app = useSelector(state => state.app);
  const auth = useSelector(state => state.auth);
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(authActions.checkUser());
  }, [dispatch]);

  console.log(auth.user); //undefined

  return (
    <ThemeProvider theme={!app.theme ? darkTheme : theme}>
      <CssBaseline />
      <React.Fragment>
        {/* TODO: Display drawer only when logged in */}
        {/* <Drawer></Drawer> */}
        <Switch>
          <Route exact path="/" component={Login} />
          <Route exact path="/dashboard">
            <Dashboard user={auth.user} /> //auth.user is undefined when this gets rendered
          </Route>
          <Route exact path="/register" component={Register} />
        </Switch>
      </React.Fragment>
    </ThemeProvider>
  );
}
  
 export const checkUser = () => async dispatch => {
  let token = localStorage.getItem("auth-token");
  if (token === null) {
    localStorage.setItem("auth-token", "");
    token = "";
  }
  const tokenRes = await Axios.post("http://localhost:5000/users/tokenIsValid", null, {
    headers: { "x-auth-token": token }
  });
  if (tokenRes.data) {
    const userRes = await Axios.get("http://localhost:5000/users/", {
      headers: { "x-auth-token": token }
    });
    dispatch({
      type: CHECK_USER,
      token,
      user: userRes.data
    });
  }
};

  

Ответ №1:

Мне нужно, чтобы useEffect запускался до того, как что-либо будет отображено. Как я мог это сделать?

Вы не можете выполнить useEffect run перед начальным рендерингом.

Точно так же, как componentDidMount в компонентах класса, выполняется после первоначального рендеринга, useEffect выполняется после первоначального рендеринга, а затем его выполнение зависит от того, передаете ли вы второй аргумент, т. Е. Массив зависимостей, в useEffect хук.

какое другое решение я должен использовать?

Вы можете условно отображать содержимое, убедившись, что вы отображаете асинхронно извлеченные данные только после того, как они станут доступны.

 return (
   { auth ? <render content> : null}
);
  

или

 return (
   { auth amp;amp; <render content> }
);
  

P.S: угловые скобки < or > не включены в синтаксис. Они просто используются в качестве заполнителя для содержимого, которое вам нужно отобразить.

Подробности см. в разделе: Реакция — условный рендеринг

Комментарии:

1. Спасибо, это работает, но, очевидно, есть небольшая задержка перед отображением содержимого рендеринга. Как я мог предотвратить эту задержку?

2. Во время загрузки данных вы можете отобразить какой-то индикатор загрузки, чтобы указать, что данные загружаются.

Ответ №2:

Альтернатива

Вы можете использовать useMemo , который не ожидает re-render . Он будет выполняться таким же образом на основе зависимостей, таких как useEffect.

 useMemo(()=>{
    doSomething() //Doesn't want until render is completed 
}, [dep1, dep2])