简体   繁体   English

使用 React,想修复 useEffect 缺少依赖错误

[英]Using React, want to fix useEffect has a missing dependency error

I can't seem to to get reed of this error for some reason;由于某种原因,我似乎无法了解这个错误; I've looked into it, callbacks, including the code in the useEffect , but it isn't working for me (or I'm doing it wrong).我已经研究过它,回调,包括useEffect的代码,但它对我不起作用(或者我做错了)。

Here is the code:这是代码:

import React, { useEffect, useState } from "react";
import "../css/main.css";
import Node from "./node";

const Pathfinder = () => {
  const START_NODE_ROW = 10;
  const START_NODE_COL = 15;
  const FINISH_NODE_ROW = 10;
  const FINISH_NODE_COL = 35;

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

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

  const getGrid = () => {
    setGrid(getInitGrid());
  };

  const getInitGrid = () => {
    const grid = [];
    for (let row = 0; row < 20; row++) {
      const currentRow = [];
      for (let col = 0; col < 50; col++) {
        currentRow.push(createNode(col, row));
      }
      grid.push(currentRow);
    }
    return grid;
  };

  const createNode = (col, row) => {
    return {
      col,
      row,
      isStart: row === START_NODE_ROW && col === START_NODE_COL,
      isFinish: row === FINISH_NODE_ROW && col === FINISH_NODE_COL,
      distance: Infinity,
      isVisited: false,
      isWall: false,
      previousNode: null
    };
  };

  return (
    <main id="Pathfinder">
      {grid.map((row, rowIdx) => {
        return (
          <div key={rowIdx}>
            {row.map((node, nodeIdx) => {
              const { row, col, isFinish, isStart } = node;
              return (
                <Node
                  key={nodeIdx}
                  col={col}
                  isFinish={isFinish}
                  isStart={isStart}
                  row={row}
                ></Node>
              );
            })}
          </div>
        );
      })}
    </main>
  );
};

export default Pathfinder;

I'm basically making a grid of Nodes components;我基本上是在制作一个由 Nodes 组件组成的网格; I have to use useEffect because I was trying to make using arrow functions only and hooks, and without classes / react components, which is why I can't use something like componentWillMount .我必须使用useEffect因为我试图只使用箭头函数和钩子,而不使用类/反应组件,这就是为什么我不能使用像componentWillMount这样的东西。

You need to pass the used objects, in your case the getGrid function to useEffect hook to remove the warning message.您需要将使用的对象(在您的情况下) getGriduseEffect钩子的getGrid函数以删除警告消息。

Just like the following:就像下面这样:

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

Additional suggestion from TJ Crowder to use useCallback for getGrid .在其他的建议TJ克罗德使用useCallbackgetGrid You can do that as the following:您可以按以下方式执行此操作:

const getGrid = useCallback(() => {
    setGrid(getInitGrid());
}, [getInitGrid]);

Read further here:在此处进一步阅读:

  1. useEffect hook useEffect钩子
  2. useCallback hook useCallback钩子

You need to do the same with getInitGrid in your code.您需要在代码中对getInitGrid执行相同的操作。

I hope this helps!我希望这有帮助!

As TJ mentioned, moving the functions getInitGrid and createNode outside of the component is the best move.正如 TJ 所提到的,将函数getInitGridcreateNode移到组件之外是最好的做法。 The way you have it right now, the functions will be redefined on every render and that isn't necessary as they are not directly tied to your components state.按照您现在的方式,函数将在每次渲染时重新定义,这不是必需的,因为它们不直接与您的组件状态相关联。

Additionally, the useState hook can use a lazy intitial state which means you can pass a function for the initial state argument, and you wouldn't need the useEffect hook at all.此外, useState钩子可以使用惰性初始状态,这意味着您可以为初始状态参数传递一个函数,而您根本不需要 useEffect 钩子。

Here is what I ended up with:这是我最终的结果:

import React, { useState } from "react";
import "../css/main.css";
import Node from "./node";

const START_NODE_ROW = 10;
const START_NODE_COL = 15;
const FINISH_NODE_ROW = 10;
const FINISH_NODE_COL = 35;

const createNode = (col, row) => {
  return {
    col,
    row,
    isStart: row === START_NODE_ROW && col === START_NODE_COL,
    isFinish: row === FINISH_NODE_ROW && col === FINISH_NODE_COL,
    distance: Infinity,
    isVisited: false,
    isWall: false,
    previousNode: null
  };
};

const getInitGrid = () => {
  const grid = [];
  for (let row = 0; row < 20; row++) {
    const currentRow = [];
    for (let col = 0; col < 50; col++) {
      currentRow.push(createNode(col, row));
    }
    grid.push(currentRow);
  }
  return grid;
};

const Pathfinder = () => {

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

  return (
    <main id="Pathfinder">
      {grid.map((row, rowIdx) => {
        return (
          <div key={rowIdx}>
            {row.map((node, nodeIdx) => {
              const { row, col, isFinish, isStart } = node;
              return (
                <Node
                  key={nodeIdx}
                  col={col}
                  isFinish={isFinish}
                  isStart={isStart}
                  row={row}
                ></Node>
              );
            })}
          </div>
        );
      })}
    </main>
  );
};

export default Pathfinder;

Most of the content within Pathfinder is static and should be moved outside it into its module; Pathfinder大部分内容都是静态的,应该从它的外部移到它的模块中; that will also have the effect of dealing with the useEffect problem you're having.这也将具有处理您遇到的useEffect问题的效果。 All of the START_NODE_ROW etc. consts, getInitGrid , and createNode are static, there's no need to recreate them every time.所有START_NODE_ROW等 consts、 getInitGridcreateNode都是静态的,无需每次都重新创建它们。 I'd also wrap getGrid in useCallback and probably reorder things slightly so that things are only used after they're defined, but that's primarily for the human reader, not the compiler/JavaScript engine:我还将getGrid包装在useCallback并可能稍微重新排序,以便仅在定义后使用,但这主要是针对人类读者,而不是编译器/JavaScript 引擎:

import React, { useEffect, useState } from "react";
import "../css/main.css";
import Node from "./node";

const START_NODE_ROW = 10;
const START_NODE_COL = 15;
const FINISH_NODE_ROW = 10;
const FINISH_NODE_COL = 35;

const getInitGrid = () => {
  const grid = [];
  for (let row = 0; row < 20; row++) {
    const currentRow = [];
    for (let col = 0; col < 50; col++) {
      currentRow.push(createNode(col, row));
    }
    grid.push(currentRow);
  }
  return grid;
};

const createNode = (col, row) => {
  return {
    col,
    row,
    isStart: row === START_NODE_ROW && col === START_NODE_COL,
    isFinish: row === FINISH_NODE_ROW && col === FINISH_NODE_COL,
    distance: Infinity,
    isVisited: false,
    isWall: false,
    previousNode: null
  };
};

const Pathfinder = () => {

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

  const getGrid = useCallback(() => {
    setGrid(getInitGrid());
  }, []);

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

  return (
    <main id="Pathfinder">
      {grid.map((row, rowIdx) => {
        return (
          <div key={rowIdx}>
            {row.map((node, nodeIdx) => {
              const { row, col, isFinish, isStart } = node;
              return (
                <Node
                  key={nodeIdx}
                  col={col}
                  isFinish={isFinish}
                  isStart={isStart}
                  row={row}
                ></Node>
              );
            })}
          </div>
        );
      })}
    </main>
  );
};

export default Pathfinder;

Separately, getGrid is tiny and used only once.另外, getGrid很小并且只使用一次。 For me, it's not worth breaking it out into its own function:对我来说,不值得把它分解成自己的功能:

import React, { useEffect, useState } from "react";
import "../css/main.css";
import Node from "./node";

const START_NODE_ROW = 10;
const START_NODE_COL = 15;
const FINISH_NODE_ROW = 10;
const FINISH_NODE_COL = 35;

const getInitGrid = () => {
  const grid = [];
  for (let row = 0; row < 20; row++) {
    const currentRow = [];
    for (let col = 0; col < 50; col++) {
      currentRow.push(createNode(col, row));
    }
    grid.push(currentRow);
  }
  return grid;
};

const createNode = (col, row) => {
  return {
    col,
    row,
    isStart: row === START_NODE_ROW && col === START_NODE_COL,
    isFinish: row === FINISH_NODE_ROW && col === FINISH_NODE_COL,
    distance: Infinity,
    isVisited: false,
    isWall: false,
    previousNode: null
  };
};

const Pathfinder = () => {

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

  useEffect(() => {
    setGrid(getInitGrid());
  }, []);

  return (
    <main id="Pathfinder">
      {grid.map((row, rowIdx) => {
        return (
          <div key={rowIdx}>
            {row.map((node, nodeIdx) => {
              const { row, col, isFinish, isStart } = node;
              return (
                <Node
                  key={nodeIdx}
                  col={col}
                  isFinish={isFinish}
                  isStart={isStart}
                  row={row}
                ></Node>
              );
            })}
          </div>
        );
      })}
    </main>
  );
};

export default Pathfinder;

(You don't have to declare setGrid or getInitGrid as dependencies, since the first is a state setter function from React that is guaranteed to be stable , and the second is defined outside Pathfinder .) (您不必将setGridgetInitGrid声明为依赖项,因为第一个是来自 React 的状态 setter 函数,它保证是 stable 的,第二个是在Pathfinder之外定义的。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM