【问题标题】:How can I call useEffect to re-render upon a particular state change如何调用 useEffect 在特定状态更改时重新渲染
【发布时间】:2020-12-04 09:27:40
【问题描述】:

我需要下面的第一个 useEffect 在更改网格状态时重新渲染。具体来说,当我将网格对象的一个​​值重新分配为 true 时,一旦在 changeWall 函数中为 grid 注册了状态更改,我需要包含 initializeGrid() 的 useEffect 重新渲染。我需要此更改以立即重新渲染 initializeGrid() 函数

import React, { useState, useEffect } from "react";


const Pathfind = () => {

  const [grid, setGrid] = useState(false);


  useEffect(() => {
    initializeGrid();
  }, []);

  const initializeGrid = () => {

    grid = new Array(X);

    for (let i = 0; i < Y; i++) {
      grid[i] = new Array(Y);
    }

    setGrid(grid);

  };

  let isMouseDown = false;

  function changeWall(e) {
    let id = e.target.id;
    grid[id.y][id.x].isWall = true;
  }

  useEffect(() => {
    document.addEventListener("mousedown", function () {
      isMouseDown = true;

      document.onmouseup = () => {
        isMouseDown = false;
        document.removeEventListener("mouseover", changeWall);
      };

      if (mouseIsDown) {
        document.addEventListener("mouseover", changeWall);
      }

    });
  }, []);

 };

export default Pathfind;

【问题讨论】:

  • 首先你的代码看起来很奇怪,我不认为你可以在功能组件之外使用反应钩子,也没有渲染?
  • 如果您在任何网格中运行您的 initializeGrid 函数,则更改其创建新网格而不进行更改,并为该网格分配设置状态,因此您将看不到任何更改
  • 我看到了循环的风险,如果您希望 useEffect 对触发更改的同一属性的更改做出反应。我建议您仅使用 useEffect 对组件外部的更改做出反应。您可能想改为运行 initializeGrid。这样,在组件首次启动时设置网格,并在需要更改网格时重置。将新值传递给 initializeGrid 而不是直接传递给 setGrid。如上所述,您的示例中缺少一些代码。

标签: reactjs rendering addeventlistener use-effect use-state


【解决方案1】:

问题

grid 状态为 const,因此尝试grid = new Array(X); 将在initializeGrid 中引发错误。也许您打算声明一个新变量来初始化/更新状态。

const grid = new Array(X);

回答

使用第二个状态来指示“墙”已更改。 true 的初始状态将允许 initializeGrid 函数在初始组件安装渲染上运行。

const [wallChanged, setWallChanged] = useState(true);

useEffect(() => {
  if (wallChanged) {
    setWallChanged(false);
    initializeGrid();
  }
}, [wallChanged]);

在处理程序中设置墙更改状态以触发重新初始化。

function changeWall(e) {
  const { id } = e.target;
  grid[id.y][id.x].isWall = true; // *
  setWallChanged(true);
}

* 注意:请注意,grid[id.y][id.x].isWall = true; 是一个状态突变。 没有太多其他上下文,虽然我不能确定这是否是一个实际问题,但这绝对是代码味道。

实际上,由于initializeGrid 完全重置了网格状态,这可能不是问题,而且实际上,wallChanged 状态“标志”可能并非完全不需要grid[id.y][id.x].isWall = true; 行。

一个更简单的解决方案可能是直接在处理程序中调用initializeGrid。没有额外的状态,grid 状态已更新,组件重新渲染至少比我之前的解决方案早 1 个渲染周期。

function changeWall(e) {
  initializeGrid();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-12
    • 2021-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-29
    • 2017-11-16
    相关资源
    最近更新 更多