Состояние в React обновляется не так, как ожидалось

#reactjs #state

#reactjs #состояние

Вопрос:

В моем главном App.js компоненте я пытаюсь обновить свое состояние

 const[isAuthenticated, setIsAuthenticated] = useState(false)
  

значение true при загрузке моего пользователя с учетом токена, который у меня есть в локальном хранилище.

 useEffect(() => {
  const loadUser = async () => {
    await fetch('http://localhost:5000/api/auth', {
      method: 'GET',
      headers: {
        'x-auth-token': localStorage.token,
      },
    });

    setIsAuthenticated(true);
  };
  
  loadUser();
}, []);
  

В моем возврате я отрисовываю частный компонент…

 <PrivateRoute exact path='/upload' component={Upload} isAuthenticated={isAuthenticated} />
  

Мой PrivateRoute.js файл выглядит следующим образом…

 const PrivateRoute = ({ component: Component, isAuthenticated, ...rest }) => (
  <Route
    {...rest}
    render={(props) =>
      isAuthenticated ? <Component {...props} /> : <Redirect to='/login' />
    }
  />
);
  

В значительной степени, передавая isAuthenticated в качестве реквизита моему PrivateRoute компоненту, я бы предположил, что isAuthenticated следует обновить до true . Я проверил, правильно ли я загружаю пользователя, проверив данные, которые я получаю из запроса, который я делаю, и действительно, я получаю пользователя и setIsAuthenticated вызывается

Однако, когда я попытался проверить, что isAuthenticated находится в моем PrivateRoute после загрузки пользователя, я получаю, что isAuthenticated это false

Я не уверен, почему это так, и был бы очень признателен за некоторую помощь и объяснение.

Мой App.js файл выглядит следующим образом…

 const App = () => {
  const [isAuthenticated, setIsAuthenticated] = useState(false);

  useEffect(() => {
    const loadUser = async () => {
      await fetch('http://localhost:5000/api/auth', {
        method: 'GET',
        headers: {
          'x-auth-token': localStorage.token,
        },
      });

      localStorage.setItem('token', localStorage.token);
      setIsAuthenticated(true);
    };

    loadUser();
  }, []);

  return (
    <Router>
      <div className='d-flex flex-row mb-5'>
        <Menu />
        <div className='d-flex flex-column mt-5 w-100'>
          <Switch>
            <Route exact path='/' component={Home} />
            <Route exact path='/login' component={SignIn} />
            <PrivateRoute
              exact
              path='/upload'
              component={Upload}
              isAuthenticated={isAuthenticated}
            />
          </Switch>
        </div>
      </div>
    </Router>
  );
};
  

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

1. Можете ли вы включить весь код компонента для рендеринга PrivateRoute компонента? Вы зарегистрировали перехват эффекта isAuthenticated в PrivateRoute , чтобы увидеть, получает ли он обновленное состояние? Какие сведения о попытках отладки вы можете предоставить?

2. В PrivateRoute консоли я зарегистрировался isAuthenticated , чтобы посмотреть, какое значение оно имеет. Я также добавил, как мой App.js файл выглядит как

3. @MichaelTorres откуда ты знаешь консоль. журнал печатается после получения пользователя? или как вы проверяете isAuthenticated внутри PrivateRoute ?

4. «В PrivateRoute я зарегистрировал консоль, прошедшую проверку подлинности, чтобы посмотреть, какое значение она имеет». И каково это значение? Вы видите, что оно обновляется в App состоянии? Вы видите, что оно обновляется при изменении состояния в App ?

5. Так и должно быть, вы уверены, что в выборке нет ошибок? Если в выборке ошибка, setIsAuthenticated не будет выполняться

Ответ №1:

Старайтесь не использовать свои реквизиты в функции обратного вызова, которые передаются.

Используйте реквизиты сразу, вот так:

 const PrivateRoute = ({ component: Component, isAuthenticated, ...rest }) => {
  return isAuthenticated ? (
    <Route {...rest} render={(props) => <Component {...props} />} />
  ) : (
    <Route {...rest} render={(props) => <Redirect to="/login" />} />
  );
};
  

Или создайте функцию обратного вызова с помощью useCallback с зависимостями:

 const PrivateRoute = ({ component: Component, isAuthenticated, ...rest }) => {
  const component = useCallback(
    (props) => {
      isAuthenticated ? <Component {...props} /> : <Redirect to="/login" />;
    },
    [isAuthenticated]
  );
  return <Route {...rest} render={component}/>
};
  

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

1. Спасибо @RobertTirta, я приму это к сведению, но это не решает мою проблему

Ответ №2:

для подобной проблемы лучшим решением является redux

в вашем app.js действие отправки для установки флага isAuthenticate

 store.dispatch(setIsAuthenticated(true))
  

в других файлах, где требуется проверка подлинности, просто используйте

 mapStateToProps
  

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

1. Спасибо, но я сделал это с помощью redux. Я пытаюсь сделать это без redux