即使存在依赖关系,如何运行一次useEffect?为什么ESLint抱怨呢?

时间:2020-07-16 20:41:05

标签: reactjs react-hooks use-effect

请考虑以下示例:

<div class="form-group" *ngFor="let todo of toDos; let i = index">
      <ul>
          <input class="form-control" name="toDo" [(ngModel)]="toDos[i]"  placeholder="To Do" style="border:none;">
      </ul>

</div>

我只想在安装时使用这种效果,仅此而已,我不在乎toDosconst userRole = sessionStorage.getItem('role'); const { data, setData, type, setTableType } = useTable([]); useEffect(() => { const getData = async () => { // fetch some data from API const fetchedData = await axios('..'); if (userRole === 'admin') { setData([...fetchedData, { orders: [] }]); } else { setData(fetchedData); } if (type === 1') { setTableType('normal'); } }; getData(); }, []); 是否已更改!

所以,现在我的问题是:

  1. 为什么ESLint抱怨userRole在 依赖数组?它甚至都不是状态!
  2. 为什么ESLint是 抱怨setData在依赖项数组中丢失 不是总是相同的参考还是会改变?
  3. 如何在不使棉绒不生气的情况下实现我想要的?还是应该直接打一条好旧的userRole行?还是这绝对是野蛮的?
  4. 为什么这表示我的代码中存在错误?我只想运行这种效果 一次使用最初可用的任何内容。

编辑: 让我重新表述一个问题:如果这些变量发生变化并且我不在乎它们的新值怎么办?尤其是当setData在同一文件中的不同位置进行更新时。我只想读取初始值并运行一次useEffect,如何实现该目标?

反响/详尽下降警告

4 个答案:

答案 0 :(得分:3)

  1. 用户角色位于useEffect中,因此是一个依赖项(如果它将更改-useEffect无效)
  2. useEffect不知道它是否相同,这就是为什么它要求依赖项
  3. 通常执行lint的操作,然后将这两个添加到依赖项数组中。
const userRole = sessionStorage.getItem('role');
const { data, setData } = useTable([]);

useEffect(() => {
  const getData = async () => {
    // fetch some data from API
    const fetchedData = await axios('..');
    
    if (userRole === 'admin') {
     setData([...fetchedData, { orders: [] }]);
    } else {
     setData(fetchedData);
    }
  };
  getData();
}, [userRole, setData]);
  1. here's Dan Abramov's take on this

“但是我只想在挂载上运行它!”,您会说。现在,请记住:如果指定deps,则该效果所使用的组件内部的所有值都必须存在。包括道具,状态,功能-组件中的任何内容。

答案 1 :(得分:0)

Linting是分析代码中潜在错误的过程。现在,当我们谈论为什么会出现棉绒错误时,我们需要了解规则是通过牢记特定功能的理想用例来设置的。

在使用useEffect钩子的情况下,一般的概念是说,如果我们有一个可能更改或可能导致逻辑流更改的值,则所有这些值都应放入依赖关系数组。

因此,数据是第一个进入的候选对象。与userRole相似,因为它被用于控制逻辑流而不是简单地作为值。

我建议采用短绒棉布的建议来忽略该错误。

答案 2 :(得分:0)

注意事项:我不建议实际使用它。这实现了错误的逻辑,并且保证在值更改时是错误的。 linter试图提供帮助,因为下面的代码引入了许多细微的错误。

但是,如果要执行此操作,则可以使用ref来存储一次性功能:

      @GET("/database/search")
    Call<List<Result>> getSongsExampleInfo(@Query("per_page") Integer per_page, @Query("page") Integer page, @Query("genre") String genre, @Query("key") String key, @Query("secret") String secret);

答案 3 :(得分:0)

编辑:更新 React 后,Eslint 似乎开始抱怨以下解决方案,所以我可能会使用 // eslint-disable-line


您是正确的,如果您希望效果在组件安装时仅运行一次,则为 useEffect 提供一个空的依赖项数组是一种可行的方法。 ESLint 警告您的问题是效果可能使用陈旧数据执行,因为它引用外部状态属性,但正如您所注意到的,为数组提供它要求的依赖项会导致效果在任何时候运行它们也会发生变化。

幸运的是,我很惊讶还没有提到一个简单的解决方案 - 将效果包装在 useCallback 中。您可以安全地将依赖项赋予 useCallback,而无需再次执行。

// Some state value
const [state, setState] = useState();

const init = useCallback(
  () => {
    // Do something which references the state
    if (state === null) {}
  }, 
  // Pass the dependency to the array as normal
  [state]
);

// Now do the effect without any dependencies
useEffect(init, []);

现在 init 会在依赖项更改时重新记忆,但除非您在其他地方调用它,否则实际上只会在下面的 useEffect 中调用它来执行。

回答您的具体问题:

  1. ESLint 抱怨 userRole 是因为 React 组件在每次渲染时都会重新运行,这意味着 userRole 将来可能会有不同的值。您可以通过将 userRole 移到您的函数之外来避免这种情况。
  2. 与之前的情况相同,虽然 setData 可能实际上总是相同的,但它存在改变的可能性,这就是为什么 ESLint 希望您将其作为依赖项包含在内。由于它是自定义钩子的一部分,因此不能将其移出您的函数,您可能应该将其包含在依赖项数组中。
  3. 查看我的主要答案
  4. 正如我在前 2 中可能已经解释过的那样,ESLint 会怀疑这是一个错误,因为这些值有可能改变,即使它们实际上并没有改变。可能只是 ESLint 没有检查“on mount”效果的特殊情况,因此如果它像任何其他可能触发多次的效果一样检查该效果,这显然会成为一个现实的错误。一般来说,如果您的 effect 只运行一次并且您当时知道数据是正确的,我认为您不需要过多担心依赖项警告。