热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

使用`useSelector`选择器在分派操作后未能实时更新状态

在使用`useSelector`选择器时,发现分派操作后状态未能实时更新。这可能是由于React组件的渲染机制或Redux的状态管理问题导致的。建议检查`useSelector`的依赖项和`dispatch`的调用时机,确保状态变化能够正确触发组件重新渲染。此外,可以考虑使用`useEffect`钩子来监听状态变化,以确保及时更新。

这里是Codesandbox。

getIDs()更新cellsinitializeCells()然后需要。但是,此更改在分派操作后不会反映出来。尽管如此,我仍然可以在Redux dev tools上看到该操作已通过,并且cells的值已相应更改。 gameStart()通过props传递到子组件cells,并通过useEffect()钩子在那里调用。我需要传递一个空数组作为该钩子的第二个参数,否则它将永远运行,因为每次调用时状态都会更新。问题在于,getIDs()首次运行后,新状态不适用于以下功能。 gameStart()似乎已经完全完成并再次被调用。我需要声明initializeCells()完成后立即更新getIDs()的状态。

cells.js

import React,{ useEffect } from "react";
import { useSelector } from "react-redux";
import Cell from "./Container/Container/Cell";
const Cells = props => {
const board = useSelector(state => state.board);
useEffect(() => {
props.gameStart();
},[]);
return (


{board.map(cell => {
return (
id={cell.id.substring(1)}
key={cell.id.substring(1)}
classname="cell"
/>
);
})}

);
};
export default Cells;

app.js

import React,{ useEffect } from "react";
import { useSelector,useDispatch } from "react-redux";
import {
setCells,setBoard
} from "../../redux/actions/index";
const Game = () => {
const dispatch = useDispatch();
const cells = useSelector(state => state.cells);
const board = useSelector(state => state.board);
const boardSize = useSelector(state => state.boardSize);
async function gameStart() {
await getIDs();
console.log(cells); // []
await initializeCells();
await assignsnake();
await placeFood();
await paintCells();
}
function getIDs() {
let cellID = "";
let collection = [];
for (let i = 1; i <= boardSize.rows; i++) {
for (let j = 1; j <= boardSize.columns; j++) {
cellID = `#cell-${i}-${j}`;
collection.push(cellID);
}
}
dispatch(setCells(collection));
console.log(cells); // []
}
function initializeCells() {
console.log(cells); // []
const board = [];
// for loop never runs because cells is empty
for (let i = 0; i board.push(cell(cells[i]));
}
dispatch(setBoard(board));
console.log("Board: ",board); // []
}
function cell(id) {
return {
id: id,row: id.match("-(.*)-")[1],column: id.substr(id.lastIndexOf("-") + 1),hasFood: false,hassnake: false
};
}
return (
...
)
}
export default Game;

reducers / index.js

import {
SET_CELLS,SET_BOARD
} from "../constants/action-types";
const initialState = {
board: [],cells: [],boardSize: {
rows: 25,columns: 40
}
};
const rootReducer = (state = initialState,action) => {
switch (action.type) {
case SET_CELLS:
return Object.assign({},state,{
cells: action.payload
});
case SET_BOARD:
return Object.assign({},{
board: action.payload
});
default:
return state;
}
};

actions / index.js

import {
SET_CELLS,SET_BOARD
} from "../constants/action-types";
export const setCells = payload => {
return { type: SET_CELLS,payload };
};
export const setBoard = payload => {
return { type: SET_BOARD,payload };
};

constants / action-types.js

export const SET_CELLS = "SET_CELLS";
export const SET_BOARD = "SET_BOARD";



我建议您在这里重新考虑所有的模式,并在编写代码之前考虑一下可以通知您的决定的内容。首先,为什么要这样设置状态?如果使用状态是合理的,那么当您仅在cells组件中访问board时,为什么要创建单独的boardCells状态值?是否会控制诸如boardSize之类的任何值?也许在应用加载时会从远程网络资源中调用它们,而您不立即知道它们吗?如果这两个都不对,则没有任何充分的理由将它们存储在状态中,它们可以只是在组件外部初始化时声明的常量。如果是,则代码应适合用例。如果要由用户控制电路板的尺寸,则应使用默认值初始化值,并处理所有同步状态更改,而在reducer内没有副作用。

此外,正如您所知,使用异步函数的方式有点像反模式。使用Redux,如果您使用的是真正的异步功能,即调用网络资源,则可以使用thunks,并在每次{{ 1}}。

否则,您是否熟悉getState()的类组件生命周期模式?本质上,您“监听”状态更改,并且仅在状态更改后调用依赖于状态更改的函数。您可以使用钩子执行此操作的一种方法是dispatch使用包含您所依赖状态的依赖项数组,这意味着只有在这些依赖项发生更改时才会调用它,并且您可以在{中进行进一步的条件检查{1}}函数(但从不有条件地包装componentDidUpdate!)。当使用对象或数组作为依赖项时,事情变得更加复杂,因为它使用严格的相等性检查,因此您可能需要使用ref并比较useEffect中的当前值和先前值,以及类似{{3} }。

所有这些,在您当前的用例中,您不需要执行任何操作,因为您只是在同步初始化静态值。如果useEffect值不受控制,我个人甚至不会将其存储在状态中,但是出于教育的目的,这是您在化简器中的操作方式。

首先,只需使用useEffect组件中的useEffect

然后,将所有同步逻辑封装在减速器中:

boardSize
,

在分派一些动作后,仅在下一次渲染时才会提供更新的存储。对于具有钩子和带有_m HOC的类的函数,这是相同的。

您需要更改代码,以免立即发生更改。对于我来说,很难理解您的意图,您可能首先要渲染它的来龙去脉,并采取行动来分而忘却。而且应该可以。

如果不这样做,请进行最少的采样(仅使用相关的钩子+数据呈现方式),并描述您要获取的内容(而不是“如何”)


推荐阅读
  • 本文详细介绍了如何构建一个高效的UI管理系统,集中处理UI页面的打开、关闭、层级管理和页面跳转等问题。通过UIManager统一管理外部切换逻辑,实现功能逻辑分散化和代码复用,支持多人协作开发。 ... [详细]
  • 本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ... [详细]
  • 本文详细介绍如何使用Python进行配置文件的读写操作,涵盖常见的配置文件格式(如INI、JSON、TOML和YAML),并提供具体的代码示例。 ... [详细]
  • 本文深入探讨了 Java 中的 Serializable 接口,解释了其实现机制、用途及注意事项,帮助开发者更好地理解和使用序列化功能。 ... [详细]
  • 本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ... [详细]
  • Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ... [详细]
  • 本文介绍如何使用Objective-C结合dispatch库进行并发编程,以提高素数计数任务的效率。通过对比纯C代码与引入并发机制后的代码,展示dispatch库的强大功能。 ... [详细]
  • 本文详细介绍了Java中org.eclipse.ui.forms.widgets.ExpandableComposite类的addExpansionListener()方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。这些示例来源于多个知名开源项目,具有很高的参考价值。 ... [详细]
  • 深入解析Spring Cloud Ribbon负载均衡机制
    本文详细介绍了Spring Cloud中的Ribbon组件如何实现服务调用的负载均衡。通过分析其工作原理、源码结构及配置方式,帮助读者理解Ribbon在分布式系统中的重要作用。 ... [详细]
  • 前言--页数多了以后需要指定到某一页(只做了功能,样式没有细调)html ... [详细]
  • 本文详细解析了Python中的os和sys模块,介绍了它们的功能、常用方法及其在实际编程中的应用。 ... [详细]
  • 本文探讨了 Objective-C 中的一些重要语法特性,包括 goto 语句、块(block)的使用、访问修饰符以及属性管理等。通过实例代码和详细解释,帮助开发者更好地理解和应用这些特性。 ... [详细]
  • 本文详细介绍了 Apache Jena 库中的 Txn.executeWrite 方法,通过多个实际代码示例展示了其在不同场景下的应用,帮助开发者更好地理解和使用该方法。 ... [详细]
  • andr ... [详细]
  • Linux 系统启动故障排除指南:MBR 和 GRUB 问题
    本文详细介绍了 Linux 系统启动过程中常见的 MBR 扇区和 GRUB 引导程序故障及其解决方案,涵盖从备份、模拟故障到恢复的具体步骤。 ... [详细]
author-avatar
路过然后错过
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有