【问题标题】:React not detecting an update in the Redux storeReact 未检测到 Redux 存储中的更新
【发布时间】:2020-05-25 20:57:36
【问题描述】:

您好,我有一个 react redux 存储,用于存储有关当前登录用户的信息。这是我的减速器和我的操作:

interface Account {
    username: string | null;
    isLoggedIn: boolean;
    role: string | null;
}

const accountReducer = (state: Account, action: any): Account | {} => {
    switch (action.type) {
        case "SET_ACCOUNT":
            return {
                username: action.payload.username,
                isLoggedIn: action.payload.isLoggedIn,
                role: action.payload.role,
            };

        case "LOGOUT_ACCOUNT":
            return {
                username: null,
                isLoggedIn: false,
                role: null,
            };

        default:
            return { ...state };
    }
};

export default accountReducer;
interface Account {
    username: string | null;
    isLoggedIn: boolean;
    role: string | null;
}

const setAccount = (account: Account) => {
    return {
        type: "SET_ACCOUNT",
        payload: account,
    };
};

const logoutAccount = () => {
    return {
        type: "LOGOUT_ACCOUNT",
        payload: {
            username: null,
            isLoggedIn: false,
            role: null,
        },
    };
};

export default { setAccount, logoutAccount };

我有一个注销按钮,它调用以下函数:

const logoutUser = async (): Promise<void> => {
        await axios({
            method: "POST",
            url: API.logout,
            withCredentials: true,
            headers: {
                "X-CSRF-TOKEN": csrf.token,
            },
        });
        dispatch(allActions.accountActions.logoutAccount());
    };

但是现在当我单击注销按钮时,我会被注销,但是我正在访问帐户属性的其他组件都没有得到更新。我尝试将window.location.reload() 放在调度功能下,但由于某种原因这并没有刷新我的窗口。如果可能,我还想避免刷新窗口,因为这是一个 SPA。

这是我需要更新的组件之一的示例:

import React from "react";
import { NavLink, Link } from "react-router-dom";
import { useSelector } from "react-redux";

import "../../css/Navbar.css";
import LoggedInDiv from "../account/LoggedInDiv";
import LoginRegisterDiv from "../account/LoginRegisterDiv";

const Navbar: React.FC = () => {
    const account = useSelector((state: any) => state.accountReducer);

    return (
        <div className="main-navbar-container">
            <div className="navbar-logo-container">
                <h1 style={{ padding: "0px", margin: "0px" }}>
                    <Link to="/" className="navbar-link">
                       Logo
                    </Link>
                </h1>
            </div>
            <div style={{ display: "flex", flexDirection: "column" }}>
                <div className="navbar-links-container">
                    <NavLink to="/builder" className="navbar-link" activeClassName="navbar-link-active">
                        Builder
                    </NavLink>
                    <NavLink
                        to="/finishedbuilds"
                        className="navbar-link"
                        activeClassName="navbar-link-active"
                    >
                        Finished Builds
                    </NavLink>
                    <NavLink to="/about" className="navbar-link" activeClassName="navbar-link-active">
                        About
                    </NavLink>
                    <NavLink to="/user/login" className="navbar-link" activeClassName="navbar-link-active">
                        Contact
                    </NavLink>
                </div>
                <div style={{ marginLeft: "21px", marginTop: "6px" }}>
                    <div className="account-container">
                        {account.isLoggedIn ? (
                            <LoggedInDiv username={account.username} />
                        ) : (
                            <LoginRegisterDiv />
                        )}
                    </div>
                </div>
            </div>
        </div>
    );
};

export default Navbar;

好的,我终于找到了问题所在。我对/logout 的axios POST 请求实际上返回了一个错误并崩溃了,所以在请求之后我什至没有到达dispatch。我只是将 axios 代码包装在一个 try catch 块中,直到我发现为什么我的后端在我尝试注销时给我错误,即使它成功注销了我。

【问题讨论】:

  • 其他组件如何访问redux store?
  • @Trisma const account = useSelector((state: any) =&gt; state.accountReducer);
  • 所以我想即使您登录account,如果您单击注销按钮,您也不会再次看到记录...似乎我也遇到了这个问题与另一个使用钩子的全局状态系统。
  • @randomboiguyhere :如果您正在跟踪 username 更改,则应该是 const account = useSelector((state: any) =&gt; state.username),如果您对登录状态感兴趣,可以将其替换为 isLoggedIn
  • @YevgenGorbunkov 但我还需要访问 isLoggedIn 属性,但我尝试更改您的代码,但没有帮助

标签: reactjs react-redux react-tsx


【解决方案1】:

首先,您应该始终将您的状态设置为初始状态

const INITIAL_STATE = {
    username: null,
    isLoggedIn: false,
    role: null
}

然后在你的减速器中将其设置为state: Account = INITIAL_STATE

这是为了防止您的商店在 undefined 被填充之前返回它。

在您的操作中使用常量类型也是一种很好的做法,以避免在 reducer 或操作中拼写错误。

当涉及到组件没有更新时,我怀疑组件没有正确连接到 redux 存储,并且如果它们没有收到存储已更改的通知(例如新道具或本地状态正在更改) ),它们不会重新渲染。

如果不查看实际代码,很难判断实际问题出在哪里。但是你应该检查所有需要重新渲染的组件,看看它们是否真的收到了更新的 redux 状态。

编辑:

const Navbar: React.FC = (props) => {
    const account = props.account;

    return ( your code );

};

const mapStateToProps = (state: any) => {
    return state.accountReducer;
};

export default connect(mapStateToProps)(Navbar);

【讨论】:

  • 这并不能真正解释问题所在。很明显redux store连接不正确,不然他也不会发到这里来。但即使使用他在问题中给出的文件结构,也不清楚出了什么问题
  • 我完全意识到这一点,但就像你说的那样,如果不查看整个代码,就不可能说出问题的确切原因。所以我解释了我认为可能是问题的地方,指向一个方向。它确实有助于回答问题不在于减速器或动作本身,我非常怀疑,而在于组件被错误地连接到商店。您如何解释所提供信息的问题?
  • @Sodnarts 我添加了一个需要在商店更新时重新渲染的组件的示例,请检查我的 OP。
  • 我对 useSelector 的工作并不多,但是如果您 console.log 记录该组件中的状态,输出是什么?它似乎根本与商店无关。你应该创建一个 mapStateToProps = (state: any) => state.accountReducer 然后你应该使用 connect(mapStateToProps)(Navbar);这应该让您可以选择使用商店中的对象 props.accountReducer,因为该组件现在已连接到商店
  • @randomboiguyhere 我更新了我的答案以使格式更好一些,但这是将组件连接到 redux 商店的一种方式
【解决方案2】:

好的,我终于找到了问题所在。我对/logout 的 axios POST 请求实际上返回了一个错误并崩溃了,所以在请求之后我什至没有到达dispatch。我只是将 axios 代码包装在一个 try catch 块中,直到我发现为什么我的后端在我尝试注销时给我错误,即使它成功注销了我。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-06
    • 2019-05-14
    • 1970-01-01
    • 2016-01-13
    • 2018-10-15
    • 1970-01-01
    • 2020-10-15
    • 2017-07-10
    相关资源
    最近更新 更多