React:useEffect(() => f(a,b), [a]) 而不禁用react-hooks/exhaustive-deps

问题描述 投票:0回答:2

我越来越频繁地以各种形式遇到这种情况:(简化示例)

const searchParameters = useState();
const sorting = useState();

// update searchParameters if the user enters someting
// update sorting if the user clicks on a column in the table

// PROBLEM: I only want to call loadEntries() if sorting changes, but I need searchParameters for it too!
useEffect(
    () => loadEntries(sorting, searchParameters),
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [sorting]
);
  1. 有没有办法在不禁用的情况下处理这种情况
    react-hooks/exhaustive-deps?
  2. (不太重要)有没有办法仅针对特定依赖项禁用
    react-hooks/exhaustive-deps
    ? (本例中为搜索参数)
javascript reactjs react-hooks eslint
2个回答
0
投票

您可以使用

ref
来保存
searchParameters
的当前值,并且由于
ref
本身不会更改(仅
current
属性),您甚至不需要将其声明为依赖项:

const searchParameters = useState();
const sorting = useState();

// init the ref
const searchParametersRef = useRef(searchParameters);

// update the ref
useEffect(() => {
  searchParametersRef.current = searchParameters;
});

useEffect(
  () => loadEntries(sorting, searchParametersRef.current), // use the ref
  [sorting]
);

据我所知,您无法禁用

react-hooks/exhaustive-dep
等特定属性,例如
searchParameters
配置仅处理规则。


0
投票

@OriDrori 的答案可以解决这个问题。

如果需要不基于参考的替代解决方案,可以查看以下帖子。 当然,这是以额外的状态和单独的 useEffect 语句为代价的。

编码亮点

a。用于排序的额外状态

  const [prevSorting, setPrevSorting] = useState();

b。两个单独的 useEffect 调用

第一个 useEffect 将为每个渲染调用,但内部逻辑将根据排序状态的变化应用。

第二个 useEffect 将仅在排序状态发生变化时调用,并将同步设置 preSorting 状态。

  useEffect(() => {
    if (sorting !== prevSorting) {
      loadEntries(sorting, searchParameters);
    }
  }); 


  useEffect(() => {
    setPrevSorting(sorting);
  }, [sorting]);

代码 - 完整列表:

App.js

import { useState, useEffect } from 'react';

function loadEntries(sorting, searchParameters) {
  console.log(`loadEntries executed with : ${sorting},${searchParameters}`);
}

export default function App() {
  const [searchParameters, setSearchParameters] = useState('');
  const [sorting, setSorting] = useState();
  const [prevSorting, setPrevSorting] = useState();

  // update searchParameters if the user enters someting
  function handleChangeSearchParameters(newValue) {
    setSearchParameters(newValue);
  }
  // update sorting if the user clicks on a column in the table
  function handleClickSorting(newValue) {
    setSorting(newValue);
  }

  // PROBLEM: I only want to call loadEntries() if sorting changes, but I need searchParameters for it too!
  useEffect(() => {
    if (sorting !== prevSorting) {
      loadEntries(sorting, searchParameters);
    }
  });

  useEffect(() => {
    setPrevSorting(sorting);
  }, [sorting]);

  return (
    <>
      <button onClick={() => handleClickSorting(Math.random())}>
        Click sorting
      </button>
      <br />
      <label>searchParameters</label>
      <br />
      <input
        value={searchParameters}
        onChange={(e) => handleChangeSearchParameters(e.target.value)}
      ></input>
    </>
  );
}

试运行

新输入的搜索参数

它没有调用 useEffect 来进行排序的更改,请查看控制台中没有记录任何内容

Browser display - A search parameter newly entered

通过单击按钮更改排序

它确实调用了 useEffect 来进行排序的更改,请查看控制台中记录了一些内容。

Browser display - A change in sorting

搜索参数更改

它没有调用 useEffect 来更改排序,请查看控制台中没有新记录的内容。

Browser display - A change in search parameter

通过单击按钮更改排序

它确实调用了 useEffect 来更改排序,请查看控制台中有新记录的内容。

Browser display - Another change in sorting

© www.soinside.com 2019 - 2024. All rights reserved.