在自定义挂钩中创建数组是在每次状态更改时重新渲染值
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,
},
});
基本上,当我在自定义挂钩中使用数组时,它会在每次任何状态更改时重新呈现并更改变量的值。
您可以看到将 testVar 的值更改为 [] 并按下两个按钮来更改状态,在每次状态更改时都会触发 useEffect,但是当值为 "".
时不会发生这种情况
我试过使用 useMemo,但没用,
有人能解决这个问题吗?
谢谢
基本要点是 "" === ""
始终为真,而 [] === []
始终为假。字符串,虽然像对象,但有点像基元,因为它们 总是 等于它们自己。另一方面,数组是特殊的 Javascript 对象,两个声明的对象永远不会严格相等。
试试吧!
console.log('"" === ""', "" === ""); // true
console.log('[] === []', [] === []); // false
当您分配 let testVar = "";
每个渲染周期时,testVar
始终等于上一个渲染的最后一个值,因此 useMemo
挂钩 returns先前计算的记忆值。
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
);
};
因为记忆值是一个 new 对象,useEffect
钩子的依赖现在看到一个新对象,即 { testVar: true } === { testVar: false }
不是假的,因为 testVar
属性 改变了,但是因为 {} === {}
也是假的,原因与 [] === []
是一样的。这是一个新的对象引用。
除此之外,不清楚您希望使用以下代码模式完成什么:
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
挂钩,因此在父组件的每个渲染周期都会重新创建任何内部内容。
如果您的问题基本上是 如何 将数组用作 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>
);
}
我在 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,
},
});
基本上,当我在自定义挂钩中使用数组时,它会在每次任何状态更改时重新呈现并更改变量的值。 您可以看到将 testVar 的值更改为 [] 并按下两个按钮来更改状态,在每次状态更改时都会触发 useEffect,但是当值为 "".
时不会发生这种情况我试过使用 useMemo,但没用,
有人能解决这个问题吗?
谢谢
基本要点是 "" === ""
始终为真,而 [] === []
始终为假。字符串,虽然像对象,但有点像基元,因为它们 总是 等于它们自己。另一方面,数组是特殊的 Javascript 对象,两个声明的对象永远不会严格相等。
试试吧!
console.log('"" === ""', "" === ""); // true
console.log('[] === []', [] === []); // false
当您分配 let testVar = "";
每个渲染周期时,testVar
始终等于上一个渲染的最后一个值,因此 useMemo
挂钩 returns先前计算的记忆值。
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
);
};
因为记忆值是一个 new 对象,useEffect
钩子的依赖现在看到一个新对象,即 { testVar: true } === { testVar: false }
不是假的,因为 testVar
属性 改变了,但是因为 {} === {}
也是假的,原因与 [] === []
是一样的。这是一个新的对象引用。
除此之外,不清楚您希望使用以下代码模式完成什么:
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
挂钩,因此在父组件的每个渲染周期都会重新创建任何内部内容。
如果您的问题基本上是 如何 将数组用作 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>
);
}