热门标签 | 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的类的函数,这是相同的。

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

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


推荐阅读
  • 大家好,我是梅巴哥er。本文将深入探讨Redux框架中的第三个实战案例,具体实现每两秒自动点击按钮以触发颜色变化的功能。该案例中,一个关键点在于是否需要使用异步操作来处理定时任务,我们将详细分析其必要性和实现方式。通过这一实例,读者可以更好地理解Redux在实际项目中的应用及其异步处理机制。 ... [详细]
  • Egg.js 中间件详解与应用实例
    Egg.js 的中间件机制与 Koa 类似,均采用洋葱模型。每当开发一个中间件时,就像是在洋葱外增加了一层。本文将通过一个简单的中间件示例,详细介绍 Egg.js 中间件的编写方法及其应用场景,帮助读者更好地理解和使用这一功能。 ... [详细]
  • Node.js 配置文件管理方法详解与最佳实践
    本文详细介绍了 Node.js 中配置文件管理的方法与最佳实践,涵盖常见的配置文件格式及其优缺点,并提供了多种实用技巧和示例代码,帮助开发者高效地管理和维护项目配置,具有较高的参考价值。 ... [详细]
  • 本文作为探讨PHP依赖注入容器系列文章的开篇,将首先通过具体示例详细阐述依赖注入的基本概念及其重要性,为后续深入解析容器的实现奠定基础。 ... [详细]
  • 在处理遗留数据库的映射时,反向工程是一个重要的初始步骤。由于实体模式已经在数据库系统中存在,Hibernate 提供了自动化工具来简化这一过程,帮助开发人员快速生成持久化类和映射文件。通过反向工程,可以显著提高开发效率并减少手动配置的错误。此外,该工具还支持对现有数据库结构进行分析,自动生成符合 Hibernate 规范的配置文件,从而加速项目的启动和开发周期。 ... [详细]
  • 在过去,我曾使用过自建MySQL服务器中的MyISAM和InnoDB存储引擎(也曾尝试过Memory引擎)。今年初,我开始转向阿里云的关系型数据库服务,并深入研究了其高效的压缩存储引擎TokuDB。TokuDB在数据压缩和处理大规模数据集方面表现出色,显著提升了存储效率和查询性能。通过实际应用,我发现TokuDB不仅能够有效减少存储成本,还能显著提高数据处理速度,特别适用于高并发和大数据量的场景。 ... [详细]
  • 优化升级版数据采集与赋值方法,专为前文内容设计
    在前一篇文章中,方法的局限性主要体现在需要传递参数,并且参数数量受限。当页面布局与所需参数不匹配时,该方法将无法正常工作。为此,我们推出了优化升级版1.1,旨在解决这些问题并提高灵活性和适用性。 ... [详细]
  • 如何在Spark数据排序过程中有效避免内存溢出(OOM)问题
    本文深入探讨了在使用Spark进行数据排序时如何有效预防内存溢出(OOM)问题。通过具体的代码示例,详细阐述了优化策略和技术手段,为读者在实际工作中遇到类似问题提供了宝贵的参考和指导。 ... [详细]
  • 织梦系统多条件联动筛选功能详细教程及删除操作指南
    多条件联动筛选功能广泛应用于图片展示、装修设计、机械设备和在线商城等场景,通常筛选条件应聚焦于用户最关心的要素,而非涵盖所有可能的选项。在DedeCMS中,多条件筛选的PHP开发并未内置删除已选条件的功能,但通过理解PHP筛选与JS筛选的不同机制,实现这一功能相对简单且易于操作。 ... [详细]
  • 基于Node.js的高性能实时消息推送系统通过集成Socket.IO和Express框架,实现了高效的高并发消息转发功能。该系统能够支持大量用户同时在线,并确保消息的实时性和可靠性,适用于需要即时通信的应用场景。 ... [详细]
  • 本文作为“实现简易版Spring系列”的第五篇,继前文深入探讨了Spring框架的核心技术之一——控制反转(IoC)之后,将重点转向另一个关键技术——面向切面编程(AOP)。对于使用Spring框架进行开发的开发者来说,AOP是一个不可或缺的概念。了解AOP的背景及其基本原理,对于掌握这一技术至关重要。本文将通过具体示例,详细解析AOP的实现机制,帮助读者更好地理解和应用这一技术。 ... [详细]
  • 本文深入探讨了 hCalendar 微格式在事件与时间、地点相关活动标记中的应用。作为微格式系列文章的第四篇,前文已分别介绍了 rel 属性用于定义链接关系、XFN 微格式增强链接的人际关系描述以及 hCard 微格式对个人和组织信息的描述。本次将重点解析 hCalendar 如何通过结构化数据标记,提高事件信息的可读性和互操作性。 ... [详细]
  • 在数据表中,我需要触发一个操作来刷新特定列的数据。例如,对于以下表格:| ID | Name | IsDeleted ||----|-------|-----------|| 1 | test | True || 2 | test2 | False |我希望在点击“更新”按钮时,能够仅刷新选定行的“IsDeleted”列。这将有助于确保数据的实时性和准确性。 ... [详细]
  • 2017年12月7日:React中实现不同组件间的路由导航
    在React应用中,实现从首页到不同组件的路由导航是常见的需求。本文介绍了如何通过配置路由来实现这一功能。具体步骤包括:1. 在首页设置路由链接,使其能够跳转到不同的目标组件;2. 确保目标组件正确配置,特别是在导入时使用默认导出(`default`),以确保路由能够正常工作。此外,文章还提供了详细的代码示例,帮助开发者更好地理解和实现这一功能。 ... [详细]
  • 本文深入探讨了 Android DrawingView 的优化技巧与实现方法,重点介绍了如何实现平滑绘制效果。通过支持常见的绘图工具和形状,以及图层变换功能,提升了用户体验。文章详细解析了绘制过程中的性能优化策略,包括减少重绘次数、使用硬件加速和优化内存管理等技术,为开发者提供了实用的参考。 ... [详细]
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社区 版权所有