Redux 订阅似乎不起作用,因此我的页眉和页脚未显示

问题描述 投票:0回答:3

我正在开发一个使用 Redux 进行状态管理的 React 应用程序。在我的布局组件中,我尝试仅在有用户时才显示页眉和页脚,但我面临一个问题,即它们都没有显示。 我知道这是因为用户仍然为空,但我可以找到解决方法,也尝试过订阅,但没有任何变化。

这是我的布局组件的简化版本:

import Routing from "../Routing/Routing";
import "./Layout.css";
import { NavLink, useLocation } from "react-router-dom";
import { authStore } from "../../redux/redux";
import { useEffect, useState } from "react";
import UserModel from "../../../models/UserModel";

function Layout(): JSX.Element {
    const { pathname } = useLocation()
    const hideHeaderPaths: string[] = ['/login']

    const [user, setUser] = useState<UserModel>();
    console.log(user)

    useEffect(() => {
        setUser(authStore.getState().user);

        const unsubscribe = authStore.subscribe(() => {
            const updatedUser = authStore.getState().user
            setUser(updatedUser);
            alert("Change")
        });
        
        setUser(authStore.getState().user);

        return () => unsubscribe();

    }, []);

    return (
        <div className="Layout" style={{ display: hideHeaderPaths.includes(pathname) ? "block" : "grid" }}>
            {!hideHeaderPaths.includes(pathname) && user  && <header><p>{`${user.firstName}  ${user.lastName}`}  |<NavLink to={"/logout"}>Logout</NavLink> </p></header>}
            <main>
                {/* <Main /> */}
                <Routing />
            </main>
            {!hideHeaderPaths.includes(pathname) && <footer>this is the footer</footer>}
        </div>
    );
}

export default Layout;

有人可以帮我理解为什么用户信息在初始渲染上没有正确显示吗?

我也尝试过在页眉和页脚中删除用户的条件渲染,但我仍然面临同样的问题。用户的名字和姓氏在初始渲染中显示为未定义。

reactjs typescript redux react-redux
3个回答
1
投票

要记住的重要一点:

useEffect
是异步的,并且总是在初始渲染之后发生。

在您的情况下,React 首次渲染您的组件并使用您在

useState
中提供的初始状态。您什么也没提供,这基本上是
undefined
的别名。这基本上就是您看到
undefined
的原因。然后一段时间后,调用
useEffect
并用正确的数据更新状态。

我建议进行以下更改:

const [user, setUser] = useState<UserModel>(authStore.getState().user);

这样,一旦组件安装完毕,您就可以到达商店,并且用户将在初始渲染时定义。


0
投票

useEffect
钩子在渲染周期的末尾运行,因此任何副作用在初始渲染中都不会出现。

这不是 React 组件订阅 Redux 存储的方式。使用

useSelector
挂钩并选择适当的状态。 不要使用
store.subscribe
和重复的本地状态。

示例:

import { useEffect, useState } from "react";
import { NavLink, useLocation } from "react-router-dom";
import { useSelector } from "react-redux"; // <-- import hook
import Routing from "../Routing/Routing";
import "./Layout.css";
import { authStore } from "../../redux/redux";
import UserModel from "../../../models/UserModel";

function Layout(): JSX.Element {
  const { pathname } = useLocation()
  const hideHeaderPaths: string[] = ['/login']

  const user = useSelector(state => state.user); // <-- subscribe to user state

  return (
    <div
      className="Layout"
      style={{ display: hideHeaderPaths.includes(pathname) ? "block" : "grid" }}
    >
      {!hideHeaderPaths.includes(pathname) && user && (
        <header>
          <p>
            {user.firstName} {user.lastName} |
            <NavLink to="/logout">Logout</NavLink>
          </p>
        </header>
      )}
      <main>
        {/* <Main /> */}
        <Routing />
      </main>
      {!hideHeaderPaths.includes(pathname) && (
        <footer>this is the footer</footer>
      )}
    </div>
  );
}

export default Layout;

0
投票

问题似乎与组件状态中用户变量的初始状态有关。当你第一次渲染组件时,用户状态是未定义的,你尝试访问它的属性(firstName和lastName),这会导致显示“未定义”值。 您可以为用户状态指定初始默认值。将其设置为 null,然后在访问其属性之前检查用户是否存在。

import Routing from "../Routing/Routing";
import "./Layout.css";
import { NavLink, useLocation } from "react-router-dom";
import { authStore } from "../../redux/redux";
import { useEffect, useState } from "react";
import UserModel from "../../../models/UserModel";

function Layout(): JSX.Element {
  const { pathname } = useLocation();
  const hideHeaderPaths: string[] = ['/login'];

  const [user, setUser] = useState<UserModel | null>(null); // Set initial state to null

  useEffect(() => {
    setUser(authStore.getState().user);

    const unsubscribe = authStore.subscribe(() => {
      const updatedUser = authStore.getState().user;
      setUser(updatedUser);
    });

   
    return () => unsubscribe();
  }, []);

  return (
    <div className="Layout" style={{ display: hideHeaderPaths.includes(pathname) ? "block" : "grid" }}>
      {!hideHeaderPaths.includes(pathname) && user && (
        <header>
          <p>{user.firstName} {user.lastName} | <NavLink to=                                            {"/logout"}>Logout</NavLink></p>
        </header>
      )}

      <main>
        {/* <Main /> */}
        <Routing />
      </main>

      {!hideHeaderPaths.includes(pathname) && <footer>this is the footer</footer>}
    </div>
  );
}

export default Layout;

这里初始用户状态为 null,如果用户值不为 null,组件只会尝试访问 firstName 和 LastName 属性。这应该可以防止在初始渲染时显示“未定义”值。一旦 Redux 存储更新了用户信息, 该组件将再次更新。

© www.soinside.com 2019 - 2024. All rights reserved.