繁体   English   中英

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

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

我在 React Native 中创建自定义钩子时遇到了 useEffect 和 useState 的问题,导致无限循环。

我创建了一个小点心来举例说明正在发生的事情:

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,
  },
});

基本上,当我在自定义挂钩中使用数组时,它会在每次 state 发生变化时重新呈现并更改变量的值。 您可以看到将 testVar 的值更改为 [] 并按下两个按钮来更改状态,每次 state 更改时都会触发 useEffect,但是当值为“”时不会发生这种情况。

我尝试使用 useMemo 但它没有用,

有人有解决这个问题的方法吗?

谢谢

基本要点是"" === ""始终为真,而[] === []始终为假。 字符串虽然类似于对象,但在某种程度上被视为原始类型,因为它们始终等于自身。 另一方面,Arrays 是特殊的 Javascript 对象,两个声明的对象永远不会严格相等。

试试吧!

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

当你分配let testVar = ""; 每个渲染周期testVar始终等于上一个渲染的最后一个值,因此useMemo挂钩返回先前计算的记忆值。

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

现在对比一下当你赋值let testVar = ""; 每个渲染周期,依赖项现在总是一个新的数组引用,因此不严格相等,并且useMemo挂钩重新计算其记忆值。

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

由于记忆值是一个的 object, useEffect挂钩的依赖项现在看到一个新的 object,即{ testVar: true } === { testVar: false }不是假的,因为testVar属性改变了,而是因为{} === {}也是错误的,原因与[] === []相同。 这是一个新的 object 参考。

除此之外,您还不清楚您希望使用以下代码模式完成什么:

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>
  );
}

useCustomHookTest挂钩在每个渲染周期都被重新声明,因此在父组件的每个渲染周期都会重新创建内部的任何内容。

如果您的问题基本上是如何使用 arrays 作为 React 钩子依赖项,那么不幸的是没有任何好的解决方案。 两个领先的解决方案要么实施深度相等性检查,要么简单地对数组进行 JSON 字符串化。

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