Redux钩子useSelector没有给出正确的状态

时间:2020-10-07 00:35:34

标签: javascript typescript redux react-redux react-hooks

我正在尝试使Redux状态脱离全局存储,并且在useSelector HOC中使用WithAuth时,我没有获得正确的状态。在我的全局状态下,有两个键:currentUsercurrentUser.isAuthenticated

在我的Redux开发工具中,isAuthenticated键显示为值true,但是当我使用该钩子时,得到false

我看过official documentation,但是如果我正确阅读,我找不到任何对我有帮助的东西。

有人可以告诉我我在做什么错吗?我是对Redux使用钩子的新手。谢谢。

withAuth.tsx

import   React,
       { useEffect }          from "react";
import { useSelector }        from "react-redux";
import { useHistory }         from "react-router-dom";
import { Routes }             from "../../constants/RoutesNames";
import { DefaultRootState }   from "../../store/reducers";

interface Props
{
    ComponentToBeRendered: React.FC<unknown>
    props?: any
};

const stateSelector = (state: DefaultRootState) => state.currentUser.isAuthenticated;

const WithAuth : React.FC<Props> = ({ ComponentToBeRendered, props }) =>
{

    const isAuthenticated = useSelector<DefaultRootState, boolean>(stateSelector);
    const history         = useHistory();

    useEffect(() =>
    {
        if (!isAuthenticated)  history.push(Routes.SIGN_IN);

    }, [ isAuthenticated, history ]);

    return (
        <ComponentToBeRendered {...props} />
    )
}

export default WithAuth;

2 个答案:

答案 0 :(得分:0)

错误值表示什么?您可以为该问题添加更多信息吗?

还请记住,您可以简化这样的语句的返回,以使代码更简洁:

   const stateSelector = (state: DefaultRootState) => state.currentUser.isAuthenticated

答案 1 :(得分:0)

事实证明,useSelector钩对Redux状态做了双重处理。如果您将console.logconsole.log("Got isAuth", isAuthenticated);)放在useEffect挂钩中,则会看到第一个日志为Got isAuth false,第二个为Got isAuth true

我不知道这是否是完整的故事,但是到目前为止,我已经重新实现了WithAuth来接受渲染的元素而不是要渲染的组件。然后,我有条件地返回该元素或呈现的登录页面。因此,

import   React                from "react";
import { useSelector }        from "react-redux";
import   AuthFlow             from "../../pages/AuthFlow";
import { DefaultRootState }   from "../../store/reducers";

interface Props
{
    ComponentToBeRendered: React.ReactElement;
};

const isAuthenticatedSelector = (state: DefaultRootState) => state.currentUser.isAuthenticated;

const WithAuth : React.FC<Props> = React.memo(({ ComponentToBeRendered }) =>
{

    const isAuthenticated = useSelector<DefaultRootState, boolean>(isAuthenticatedSelector);

    return (
      isAuthenticated ? ComponentToBeRendered : <AuthFlow />
    )
})

export default WithAuth;

我不知道这是否是最好的方法,但是我现在已经找到了解决方法。奇怪的是useSelector不能仅在第一次运行时正确获得Redux状态。也许我想不到有人可以给我看的东西。

=========== 编辑 ==========

我对此进行了更多思考,出于各种原因,我认为这种方法可能会更好

import   React                from "react";
import { useSelector }        from "react-redux";
import   BasicTextLink        from "../../components/BasicLink/BasicLink";
import { Routes }             from "../../constants/RoutesNames";
import { DefaultRootState }   from "../../store/reducers";

interface Props
{
    ElementToBeShown: React.ReactElement;
};

const isAuthenticatedSelector = (state: DefaultRootState) => state.currentUser.isAuthenticated;

const WithAuth : React.FC<Props> = React.memo(({ ElementToBeShown }) =>
{

    const isAuthenticated = useSelector<DefaultRootState, boolean>(isAuthenticatedSelector);

    return (
      isAuthenticated ? ElementToBeShown : <h2>You are not signed in. Please {
        <BasicTextLink baseColor useHoverEffect darkHover to={Routes.SIGN_IN} underline={"hover"}>
          sign in
        </BasicTextLink>
        } first</h2>
    )
});

export default WithAuth;