【问题标题】:How to conditionally render in a react component with state updated in useEffect?如何在useEffect中更新状态的react组件有条件地渲染?
【发布时间】:2021-02-21 22:18:15
【问题描述】:

在反应中,我有一个私有路由组件,它有一个 isAuthenticated 状态值,用于渲染它正在包装的组件,或重定向回我的登录页面。

为了检测刷新并执行身份验证检查,我添加了一个useEffect 挂钩,希望我可以检查身份验证状态,然后更新isAuthenticated,然后返回组件或相应地重定向。

const PrivateRoute: React.FC<IPrivateRouteProps> = (props) => {
    const dispatch = useDispatch();
    const [isAuthenticated, setIsAuthenticated] = React.useState(false);

    useEffect(() => {
        authService.getIdentity().then(response => {
            if (response) {
                dispatch(signIn(new Identity(response.account)));
                setIsAuthenticated(true);
            } else {
                setIsAuthenticated(false);
            }         
        });
    }, [])

    return isAuthenticated ? (
        <Route {...props} component={props.component} render={undefined} />
    ) : (
        <Redirect to={{ pathname: props.redirectPath }} />
    );
};

很遗憾,这不起作用,我不确定为什么或如何解决它。

isAuthenticated 的值在渲染时始终为 false,我在控制台中收到以下错误......

index.js:1 Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
    in PrivateRoute (at App.tsx:23)

我可以确认它确实流向了setIsAuthenticated(true),但这在渲染之前从未反映在isAuthenticated 的值中。

我该如何/应该如何解决这个问题?

谢谢,

【问题讨论】:

    标签: reactjs react-hooks


    【解决方案1】:

    如您所见,上面写着Can't perform a React state update on an unmounted component.。 为了防止这个问题,你能不能试着像这样把&lt;Route&gt;&lt;Redirect&gt;放在&lt;React.Fragment&gt;里面?

    return isAuthenticated ? (
        <React.Fragment>
            <Route {...props} component={props.component} render={undefined} />
        </React.Fragment>
    ) : (
        <React.Fragment>
            <Redirect to={{ pathname: props.redirectPath }} />
        </React.Fragment>
    );
    

    【讨论】:

      【解决方案2】:

      我认为问题在于代码第一次运行时,它使用 isAuthenticated false 评估渲染,然后 useEffect 启动并尝试更新值,但您已经被重定向到另一个页面。

      我会建议使用另一个变量来知道身份验证是否已经过验证,并且只有在身份验证完成后才能继续。

      const PrivateRoute: React.FC<IPrivateRouteProps> = (props) => {
          const dispatch = useDispatch();
          const [loading, setLoading] = React.useState(true);
          const [isAuthenticated, setIsAuthenticated] = React.useState(false);
      
          useEffect(() => {
              authService.getIdentity().then(response => {
                  if (response) {
                      dispatch(signIn(new Identity(response.account)));
                      setIsAuthenticated(true);
                  } else {
                      setIsAuthenticated(false);
                  }
                  setLoading(false);         
              });
          }, [])
      
          if (isLoading) {
              //we are not ready yet
             return null;
          }
      
          return isAuthenticated ? (
              <Route {...props} component={props.component} render={undefined} />
          ) : (
              <Redirect to={{ pathname: props.redirectPath }} />
          );
      };
      

      【讨论】:

      • 有趣。它确实有效,但我只需要清楚如何。我以前从未在反应功能组件中看到钩子或方法之外的 if 语句。因此,第一次加载组件时,它将在useEffect 中的异步操作完成之前从if (isLoading) 返回null。当异步操作完成后loading 变为false 时,是否再次检查if (isLoading)?塔
      猜你喜欢
      • 2020-05-16
      • 1970-01-01
      • 2020-10-24
      • 1970-01-01
      • 1970-01-01
      • 2019-10-28
      • 1970-01-01
      • 1970-01-01
      • 2020-08-18
      相关资源
      最近更新 更多