javascript - 在自定义 Hook 中创建数组会在每次状态更改时重新渲染值

标签 javascript reactjs react-native react-hooks

我在 React Native 中创建自定义钩子(Hook),遇到了 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,
  },
});

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

我尝试使用 useMemo 但它不起作用,

有人能解决这个问题吗?

谢谢

最佳答案

基本要点是 ""=== "" 始终为 true,而 [] === [] 始终为 false。字符串虽然像对象,但在某种程度上被视为基元,因为它们总是等于它们自己。另一方面,数组是特殊的 Javascript 对象,两个声明的对象永远不会严格相等。

试试吧!

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

当您在每个渲染周期分配 let testVar = ""; 时,testVar 始终等于上一次渲染的最后一个值,因此 useMemo 钩子(Hook)返回之前计算的、内存的值。

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

现在对比一下,当您在每个渲染周期分配 let testVar = ""; 时,依赖项现在始终是一个新的数组引用,因此不严格相等,并且 useMemo 钩子(Hook)重新计算其内存值。

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

由于内存值是一个对象,useEffect钩子(Hook)的依赖现在看到一个新对象,即{ testVar: true } === { testVar: false } 不是 false,因为 testVar 属性已更改,而是因为 {} === {} 是出于同样的原因 [] === [] 也是 false。这是一个新的对象引用。

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

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 钩子(Hook)在每个渲染周期都会重新声明,因此父组件的每个渲染周期都会重新创建任何内部内容。

如果您的问题基本上是如何使用数组作为 React hook 依赖项,那么不幸的是没有任何好的解决方案。两个领先的解决方案要么实现深度相等检查,要么简单地对数组进行 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>
  );
}

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

关于javascript - 在自定义 Hook 中创建数组会在每次状态更改时重新渲染值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72093872/

相关文章:

javascript - setInterval 不适用于 useState Hook

javascript - 将多个 Javascript 对象合并为一个。 Stream.call(this) 是做什么的?

javascript - 能否使内部链接在客户端生成的 HTML 页面中起作用?

javascript - 访问 d3 包布局中的比例因子

javascript - 尝试在悬停时定位每个图像,而不是同时定位所有图像

node.js - 世博会启动后崩溃

javascript - 在项目中使用 Google Apps 脚本函数

javascript - Create React App 提供的 react-scripts 包需要依赖 :

javascript - 我如何进行同步 ReactDOM.render

javascript - 获取带有一些 header 的 POST