如何将 useEffect 挂钩与依赖列表一起用作对象数组中的特定字段?
How to use useEffect hook with the dependency list as a specific field in an array of objects?
假设我有一个这样的数组:
[
{
country: '',
'city/province': '',
street: ''
},
{
country: '',
'city/province': '',
street: ''
}
]
每次数组中任何项目中的 'country' 字段的值发生变化时,如何让 useEffect()
挂钩 运行?
我认为您不能在依赖项数组中专门解决它,但是,您可以在 useEffect
中进行检查以获得相同的总体结果。
基本上,依赖数组传递了完整的数据状态,这将在每次更改时触发效果,然后您进一步检查子属性是否已更改。
为简洁起见,我使用 lodash,但您可以 运行 任何函数来确定数据是否已更改。
代码笔:https://codepen.io/chrisk7777/pen/mdMvpvo?editors=0010
const { useState, useEffect, useRef } = React;
const { render } = ReactDOM;
const { isEqual, map } = _;
const App = () => {
const [data, setData] = useState([
{
country: "",
"city/province": "",
street: ""
},
{
country: "",
"city/province": "",
street: ""
}
]);
const prevData = useRef(data);
// hacky updates just to demonstrate the change
// change country - should trigger useEffect
const update1 = () => {
setData((s) => [s[0], { ...s[1], country: s[1].country + "a" }]);
};
// change street - should not trigger useEffect
const update2 = () => {
setData((s) => [s[0], { ...s[1], street: s[1].street + "a" }]);
};
useEffect(() => {
if (!isEqual(map(prevData.current, "country"), map(data, "country"))) {
console.log("country changed");
}
prevData.current = data;
}, [data]);
return (
<div>
<button onClick={update1}>change country - trigger effect</button>
<br />
<button onClick={update2}>change street - do not trigger effect</button>
</div>
);
};
render(<App />, document.getElementById("app"));
只需将国家映射到效果依赖数组即可。
const countries = data.map((x) => x.country);
useEffect(() => {
console.log(countries);
}, countries);
通常你不想这样做,但只是为了回答你的问题,这是可以做到的,所以让我提出以下建议,假设你的列表被称为 items
:
useEffect(() => {
}, [...items.map(v => v.country)])
上面的代码所做的是将所有 items
(及其 country
属性)散布到 useEffect
依赖数组中。
之所以这可以是临时的,主要是因为React不喜欢有可变长度的依赖。在源代码中,当长度发生变化时,它只欣赏现有元素的元素变化。因此,如果您从 1 个元素切换到 2 个元素,您可能 运行 会遇到问题。
但是,如果您有固定数量的元素,这应该可以满足您的要求。请记住 items
必须始终是一个数组。
注意:为了解决长度问题,也许我们可以向依赖数组添加一个额外的变量 length
:)
}, [items.length, ...items.map(v => v.country)])
正如我提到的,大多数情况下,您应该避免这样做,而是每次更改项目时都尝试更改整个 items
。并让Item
显示优化,如React.memo
.
假设我有一个这样的数组:
[
{
country: '',
'city/province': '',
street: ''
},
{
country: '',
'city/province': '',
street: ''
}
]
每次数组中任何项目中的 'country' 字段的值发生变化时,如何让 useEffect()
挂钩 运行?
我认为您不能在依赖项数组中专门解决它,但是,您可以在 useEffect
中进行检查以获得相同的总体结果。
基本上,依赖数组传递了完整的数据状态,这将在每次更改时触发效果,然后您进一步检查子属性是否已更改。
为简洁起见,我使用 lodash,但您可以 运行 任何函数来确定数据是否已更改。
代码笔:https://codepen.io/chrisk7777/pen/mdMvpvo?editors=0010
const { useState, useEffect, useRef } = React;
const { render } = ReactDOM;
const { isEqual, map } = _;
const App = () => {
const [data, setData] = useState([
{
country: "",
"city/province": "",
street: ""
},
{
country: "",
"city/province": "",
street: ""
}
]);
const prevData = useRef(data);
// hacky updates just to demonstrate the change
// change country - should trigger useEffect
const update1 = () => {
setData((s) => [s[0], { ...s[1], country: s[1].country + "a" }]);
};
// change street - should not trigger useEffect
const update2 = () => {
setData((s) => [s[0], { ...s[1], street: s[1].street + "a" }]);
};
useEffect(() => {
if (!isEqual(map(prevData.current, "country"), map(data, "country"))) {
console.log("country changed");
}
prevData.current = data;
}, [data]);
return (
<div>
<button onClick={update1}>change country - trigger effect</button>
<br />
<button onClick={update2}>change street - do not trigger effect</button>
</div>
);
};
render(<App />, document.getElementById("app"));
只需将国家映射到效果依赖数组即可。
const countries = data.map((x) => x.country);
useEffect(() => {
console.log(countries);
}, countries);
通常你不想这样做,但只是为了回答你的问题,这是可以做到的,所以让我提出以下建议,假设你的列表被称为 items
:
useEffect(() => {
}, [...items.map(v => v.country)])
上面的代码所做的是将所有 items
(及其 country
属性)散布到 useEffect
依赖数组中。
之所以这可以是临时的,主要是因为React不喜欢有可变长度的依赖。在源代码中,当长度发生变化时,它只欣赏现有元素的元素变化。因此,如果您从 1 个元素切换到 2 个元素,您可能 运行 会遇到问题。
但是,如果您有固定数量的元素,这应该可以满足您的要求。请记住 items
必须始终是一个数组。
注意:为了解决长度问题,也许我们可以向依赖数组添加一个额外的变量 length
:)
}, [items.length, ...items.map(v => v.country)])
正如我提到的,大多数情况下,您应该避免这样做,而是每次更改项目时都尝试更改整个 items
。并让Item
显示优化,如React.memo
.