为什么传递给备忘录的道具不存储价值
Why the props that are passed to memo are don't store the value
我正在尝试使用手动道具比较的 React 备忘录功能优化我的 React 列表渲染。我生成了一个简单的 "toggle" 按钮列表:
import React, { useState } from "react";
import "./styles.css";
import { Toggle } from "./Toggle";
export default function App() {
const [list, setList] = useState({ a: true, b: true, c: true });
const handleClick = x => {
console.log(list);
const currentValue = list[x];
setList({ ...list, [x]: !currentValue });
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
{Object.keys(list).map(x => (
<Toggle key={x} isChecked={list[x]} name={x} onChange={handleClick} />
))}
</div>
);
}
这是 "toggle" 按钮:
import React from "react";
const areEqual = (prevProps, nextProps) => {
return prevProps.isChecked === nextProps.isChecked;
};
const ToggleComponent = ({ isChecked, name, onChange }) => {
return (
<>
<h1>{isChecked ? "This is true" : "This is false"}</h1>
<button onClick={() => onChange(name)}>{name}</button>
</>
);
};
export const Toggle = React.memo(ToggleComponent, areEqual);
我的问题是列表对象实际上没有存储预期值。每次我点击按钮我得到相同的,默认一个 { a: true, b: true, c: true }
(它在 handleClick
的 console.log
中可见),但是如果我删除 areEqual
功能,一切再次正常工作,列表对象已按应有的方式更新。
编辑:
我看到,如果我将整个事物更改为一个数组并将每个按钮包装到一个对象中,备忘录功能将按预期工作。
这是因为 handleClick
函数被创建并传递给 Toggle
组件一次。
并且 handleClick's
闭包包含旧的 list
值,因此每当旧值更改时它都不会更新。
最简单的解决方法是利用状态更新器的第二个签名:一个在参数中接受旧状态值的函数。
所以每当它被调用时,react 都会将旧的状态值传递给它。
const handleClick = x => {
setList(old => ({ ...old, [x]: !old[x] }));
};
您还需要 memoize
handleClick 函数,因为 it is recreated at each render
组件保持状态:
const handleClick = React.useCallback(x => {
setList(old => ({ ...old, [x]: !old[x] }));
}, [setList]);
这里正在工作codesandbox
我正在尝试使用手动道具比较的 React 备忘录功能优化我的 React 列表渲染。我生成了一个简单的 "toggle" 按钮列表:
import React, { useState } from "react";
import "./styles.css";
import { Toggle } from "./Toggle";
export default function App() {
const [list, setList] = useState({ a: true, b: true, c: true });
const handleClick = x => {
console.log(list);
const currentValue = list[x];
setList({ ...list, [x]: !currentValue });
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
{Object.keys(list).map(x => (
<Toggle key={x} isChecked={list[x]} name={x} onChange={handleClick} />
))}
</div>
);
}
这是 "toggle" 按钮:
import React from "react";
const areEqual = (prevProps, nextProps) => {
return prevProps.isChecked === nextProps.isChecked;
};
const ToggleComponent = ({ isChecked, name, onChange }) => {
return (
<>
<h1>{isChecked ? "This is true" : "This is false"}</h1>
<button onClick={() => onChange(name)}>{name}</button>
</>
);
};
export const Toggle = React.memo(ToggleComponent, areEqual);
我的问题是列表对象实际上没有存储预期值。每次我点击按钮我得到相同的,默认一个 { a: true, b: true, c: true }
(它在 handleClick
的 console.log
中可见),但是如果我删除 areEqual
功能,一切再次正常工作,列表对象已按应有的方式更新。
编辑:
我看到,如果我将整个事物更改为一个数组并将每个按钮包装到一个对象中,备忘录功能将按预期工作。
这是因为 handleClick
函数被创建并传递给 Toggle
组件一次。
并且 handleClick's
闭包包含旧的 list
值,因此每当旧值更改时它都不会更新。
最简单的解决方法是利用状态更新器的第二个签名:一个在参数中接受旧状态值的函数。
所以每当它被调用时,react 都会将旧的状态值传递给它。
const handleClick = x => {
setList(old => ({ ...old, [x]: !old[x] }));
};
您还需要 memoize
handleClick 函数,因为 it is recreated at each render
组件保持状态:
const handleClick = React.useCallback(x => {
setList(old => ({ ...old, [x]: !old[x] }));
}, [setList]);
这里正在工作codesandbox