反应如何记忆一个组件,该组件接收一个非常嵌套的 object/array 作为 prop
React how to memoize a component that receives a very nested object/array as prop
React.memo
使用浅比较来确定 props 是否相等,但我需要传递一个对象或数组作为 prop,所以我进入了 areEqual
条件,但是 currentProps
和 nextProps
值始终相同。我的意思是,该组件不呈现。
这么说吧:
export default function App() {
const [data, setData] = useState([
{
name: "First name",
amount: 0
},
{
name: "Other name",
amount: 0
}
]);
const [value, setValue] = useState("");
return (
<>
<input
type="text"
placeholder="Type in for test"
value={value}
onChange={(e) => {
setValue(e.target.value);
}}
/>
<br />
<input
type="button"
value="Click to increment first!"
onClick={() => {
const temp = [...data];
temp[0].amount += 1;
setData(temp);
}}
/>
<input
type="button"
value="Click to increment other!"
onClick={() => {
const temp = [...data];
temp[1].amount += 1;
setData(temp);
}}
/>
<br />
<Child data={data} />
</>
);
}
和
const Child = ({ data }) => {
const count = useRef(0);
return (
<>
{data &&
data.map((obj, index) => {
return obj.name + "-" + obj.amount;
})}
<br />
Count: {count.current++}
</>
);
};
const areEqual = (currentProps, nextProps) => {
console.log(currentProps.data[0].amount, nextProps.data[0].amount);
console.log(currentProps.data[1].amount, nextProps.data[1].amount);
if (
currentProps.data[0].amount === nextProps.data[0].amount &&
currentProps.data[1].amount === nextProps.data[1].amount
) {
return true;
}
return false;
};
export default memo(Child, areEqual);
但无论 currentProps 和 nextProps 总是返回相同的值:
一切都在 this sandbox。我在这里错过了什么?
问题出在对象突变上。而是创建一个新的对象引用。
不要
const temp = [...data];
temp[0].amount += 1;
setData(temp);
做
setData(
data.map((item, index) =>
index === 0 ? { ...item, amount: item.amount + 1 } : item
)
);
也有效(使用临时变量)
如果您更喜欢使用 temp
变量的变异样式,则应避免使用相同的对象引用:
const temp = [...data];
temp[0] = { ...temp[0], amount: temp[0].amount + 1 };
setData(temp);
为什么?
but no matter what always currentProps and nextProps are returning the very same value
currentProps
和 nextProps
不同(data
prop 的引用不同)。您可以通过将 console.log(currentProps.data === nextProps.data)
添加到 areEquals
函数来检查它(它将 return false
)。
通过重复使用相同的对象引用,当您对一个对象(例如索引为 0 的对象)进行更改时,它会在 currentProps.data[0]
和 nextProps.data[0]
中更新。您可以通过将 console.log(currentProps.data[0] === nextProps.data[0])
添加到 areEquals
函数来检查它(它将 return true
)。
React.memo
使用浅比较来确定 props 是否相等,但我需要传递一个对象或数组作为 prop,所以我进入了 areEqual
条件,但是 currentProps
和 nextProps
值始终相同。我的意思是,该组件不呈现。
这么说吧:
export default function App() {
const [data, setData] = useState([
{
name: "First name",
amount: 0
},
{
name: "Other name",
amount: 0
}
]);
const [value, setValue] = useState("");
return (
<>
<input
type="text"
placeholder="Type in for test"
value={value}
onChange={(e) => {
setValue(e.target.value);
}}
/>
<br />
<input
type="button"
value="Click to increment first!"
onClick={() => {
const temp = [...data];
temp[0].amount += 1;
setData(temp);
}}
/>
<input
type="button"
value="Click to increment other!"
onClick={() => {
const temp = [...data];
temp[1].amount += 1;
setData(temp);
}}
/>
<br />
<Child data={data} />
</>
);
}
和
const Child = ({ data }) => {
const count = useRef(0);
return (
<>
{data &&
data.map((obj, index) => {
return obj.name + "-" + obj.amount;
})}
<br />
Count: {count.current++}
</>
);
};
const areEqual = (currentProps, nextProps) => {
console.log(currentProps.data[0].amount, nextProps.data[0].amount);
console.log(currentProps.data[1].amount, nextProps.data[1].amount);
if (
currentProps.data[0].amount === nextProps.data[0].amount &&
currentProps.data[1].amount === nextProps.data[1].amount
) {
return true;
}
return false;
};
export default memo(Child, areEqual);
但无论 currentProps 和 nextProps 总是返回相同的值:
一切都在 this sandbox。我在这里错过了什么?
问题出在对象突变上。而是创建一个新的对象引用。
不要
const temp = [...data];
temp[0].amount += 1;
setData(temp);
做
setData(
data.map((item, index) =>
index === 0 ? { ...item, amount: item.amount + 1 } : item
)
);
也有效(使用临时变量)
如果您更喜欢使用 temp
变量的变异样式,则应避免使用相同的对象引用:
const temp = [...data];
temp[0] = { ...temp[0], amount: temp[0].amount + 1 };
setData(temp);
为什么?
but no matter what always currentProps and nextProps are returning the very same value
currentProps
和 nextProps
不同(data
prop 的引用不同)。您可以通过将 console.log(currentProps.data === nextProps.data)
添加到 areEquals
函数来检查它(它将 return false
)。
通过重复使用相同的对象引用,当您对一个对象(例如索引为 0 的对象)进行更改时,它会在 currentProps.data[0]
和 nextProps.data[0]
中更新。您可以通过将 console.log(currentProps.data[0] === nextProps.data[0])
添加到 areEquals
函数来检查它(它将 return true
)。