简体   繁体   English

在自定义挂钩中创建数组是在每次 state 更改时重新呈现值

[英]Creating an array in the custom hook is re rendering value at every state change

I was creating a custom hook in react native and encountered a problem with useEffect and useState, resulting in an infinite loop.我在 React Native 中创建自定义钩子时遇到了 useEffect 和 useState 的问题,导致无限循环。

I created a little snack to exemplify what is happening:我创建了一个小点心来举例说明正在发生的事情:

import React, { useEffect, useState, useMemo } from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';

export default function App() {
   const [testStateVariable, setTestStateVariable] = useState(false);

    const useCustomHookTest = () => {
        let testVar = ""; // Change the value "" to [] to see the problem;
        return useMemo(
            () => ({
                testVar,
            }),
            [testVar],
            );
    };
    
    var { testVar } = useCustomHookTest();
    
    useEffect(() => {
        console.log("CHANGE OF testVar!")
    }, [testVar]);

    return (
        <View style={styles.container}>
             <Button title="Change a state to true" onPress={() => {setTestStateVariable(true)}}/>
             <Button title="Change a state to false" onPress={() => {setTestStateVariable(false)}}/>
        </View>
    );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    backgroundColor: '#ecf0f1',
    padding: 8,
  },
});

Basically, when I use an array inside a custom hook, it re-renders and changes the value of the variable every time any state changes.基本上,当我在自定义挂钩中使用数组时,它会在每次 state 发生变化时重新呈现并更改变量的值。 You can see this changing the value of testVar to [] and press the two buttons to change the states, the useEffect is fired at every state change, but this doesn't happen when the value is "".您可以看到将 testVar 的值更改为 [] 并按下两个按钮来更改状态,每次 state 更改时都会触发 useEffect,但是当值为“”时不会发生这种情况。

I tried using useMemo but it didn't work,我尝试使用 useMemo 但它没有用,

Does someone have a solution for this problem?有人有解决这个问题的方法吗?

Thanks谢谢

The basic gist is that "" === "" is always true, while [] === [] is always false.基本要点是"" === ""始终为真,而[] === []始终为假。 Strings, although are like objects, are kind of treated like primitives, in that they will always be equal to themselves.字符串虽然类似于对象,但在某种程度上被视为原始类型,因为它们始终等于自身。 Arrays on the other hand, are special Javascript objects and two declared objects are never strictly equal to each other.另一方面,Arrays 是特殊的 Javascript 对象,两个声明的对象永远不会严格相等。

Try it!试试吧!

 console.log('"" === ""', "" === ""); // true console.log('[] === []', [] === []); // false

When you assign let testVar = "";当你分配let testVar = ""; each render cycle the testVar is always equal to the last the value from the previous render and and so the useMemo hook returns the previously computed, memoized value.每个渲染周期testVar始终等于上一个渲染的最后一个值,因此useMemo挂钩返回先前计算的记忆值。

const useCustomHookTest = () => {
  let testVar = "";
  return useMemo(
    () => ({
      testVar
    }),
    [testVar] // "" === "" true, dependency didn't "change".
  );
};

Contrast this now when you assign let testVar = "";现在对比一下当你赋值let testVar = ""; each render cycle, the dependency is now always a new array reference and thus not strictly equal and the useMemo hook recomputes its memoized value.每个渲染周期,依赖项现在总是一个新的数组引用,因此不严格相等,并且useMemo挂钩重新计算其记忆值。

const useCustomHookTest = () => {
  let testVar = []; // <-- new array each render
  return useMemo(
    () => ({
      testVar
    }),
    [testVar] // [] === [] false, new memoized value
  );
};

Since the memoized value is a new object, the dependency for the useEffect hook now sees a new object, ie { testVar: true } === { testVar: false } isn't false because the testVar property changed, but because {} === {} is also false for the same reason [] === [] is.由于记忆值是一个的 object, useEffect挂钩的依赖项现在看到一个新的 object,即{ testVar: true } === { testVar: false }不是假的,因为testVar属性改变了,而是因为{} === {}也是错误的,原因与[] === []相同。 It's a new object reference.这是一个新的 object 参考。

Beyond this it is unclear what you hope to accomplish with the following code pattern:除此之外,您还不清楚您希望使用以下代码模式完成什么:

export default function App() {
  const [testStateVariable, setTestStateVariable] = useState(false);

  const useCustomHookTest = () => {
    let testVar = "";
    return useMemo(
      () => ({
        testVar
      }),
      [testVar]
    );
  };

  var { testVar } = useCustomHookTest();

  useEffect(() => {
    console.log("CHANGE OF testVar!");
  }, [testVar]);

  return (
    <View style={styles.container}>
      <Text>{testStateVariable.toString()}</Text>
      <Button
        title="Change a state to true"
        onPress={() => {
          setTestStateVariable(true);
        }}
      />
      <Button
        title="Change a state to false"
        onPress={() => {
          setTestStateVariable(false);
        }}
      />
    </View>
  );
}

The useCustomHookTest hook is redeclared each render cycle, so anything internal is recreated each render cycle of the parent component. useCustomHookTest挂钩在每个渲染周期都被重新声明,因此在父组件的每个渲染周期都会重新创建内部的任何内容。

If your question is basically how to use arrays as React hook dependencies then unfortunately there aren't any great solutions.如果您的问题基本上是如何使用 arrays 作为 React 钩子依赖项,那么不幸的是没有任何好的解决方案。 The two leading solutions are either to implement a deep equality check, or to simply JSON stringify the array.两个领先的解决方案要么实施深度相等性检查,要么简单地对数组进行 JSON 字符串化。

JSON.stringify Example: JSON.stringify 示例:

const useCustomHookTest = () => {
  let testVar = [];
  return { testVar };
};

export default function App() {
  const [testStateVariable, setTestStateVariable] = useState(false);

  const { testVar } = useCustomHookTest();

  useEffect(() => {
    console.log("CHANGE OF testVar!");
  }, [JSON.stringify(testVar)]); // <-- JSON stringify dependency

  return (
    <View style={styles.container}>
      <Text>{testStateVariable.toString()}</Text>
      <Button
        title={`Change a state to ${(!testStateVariable).toString()}`}
        onPress={() => {
          setTestStateVariable((t) => !t);
        }}
      />
    </View>
  );
}

编辑 creating-an-array-in-the-custom-hook-is-re-rendering-value-at-every-state-change

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

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