更改数组中的一个状态会导致在 React Hooks 中重新渲染整个循环生成的自定义组件
Posted
技术标签:
【中文标题】更改数组中的一个状态会导致在 React Hooks 中重新渲染整个循环生成的自定义组件【英文标题】:Changing one state in an array causes a re-rendering of the entire loop-generated custom components in React Hooks 【发布时间】:2020-04-18 16:11:16 【问题描述】:我正在使用 React Hooks。我正在从地图中填充按钮列表。每个按钮在disabled
属性上都有自己的状态。填充它们后,当单击按钮时,我想将该按钮设置为禁用。
const initialBtnDisabled = [false, false, false, false, false, false, false, false];
const [btnDisabled, setBtnDisabled] = useState(initialBtnDisabled);
const onChange = event =>
const btnIndex = event.target.value;
let btnDisabledcopy = [...btnDisabled]
btnDisabledcopy[btnIndex] = true
setBtnDisabled(btnDisabledcopy)
const Button = (props) =>
console.log("I am from button");
const btnIndex = props
return (
<button onClick=onChange value=btnIndex disabled=btnDisabled[btnIndex]>click me</button>
)
const btnArr = [1, 2, 3, 4, 5, 6, 7, 8]
const btnFields = btnArr.map((item, index) =>
<td key=index>
<Button btnIndex=index />
</td>
);
return (
<tr>btnFields</tr>
)
现在这可行,但问题在于每次单击按钮时,Button 组件都会再次为整个循环重新渲染,而我只更改了数组的一个状态。我在Button
组件中的console.log
每次点击都会记录8 次。
如何防止这种情况发生?
【问题讨论】:
只需在 Button 组件中使用标量禁用状态值 【参考方案1】:您可以使用 React PureComponent 防止重新渲染。 如果传递的 props 被更新,这只会重新渲染组件。
const initialBtnDisabled = [false, false, false, false, false, false, false, false];
const [btnDisabled, setBtnDisabled] = useState(initialBtnDisabled);
const onChange = event =>
const btnIndex = event.target.value;
let btnDisabledcopy = [...btnDisabled]
btnDisabledcopy[btnIndex] = true
setBtnDisabled(btnDisabledcopy)
class Button extends React.PureComponent
render ()
console.log("I am from button");
const btnIndex = this.props;
return (
<button onClick=onChange value=btnIndex disabled=btnDisabled[btnIndex]>click me</button>
)
const btnArr = [1, 2, 3, 4, 5, 6, 7, 8]
const btnFields = btnArr.map((item, index) =>
<td key=index>
<Button btnIndex=index />
</td>
);
return (
<tr>btnFields</tr>
)
【讨论】:
这仍然重新渲染 @reddy 单击一个按钮是否仍然记录 8 次? 是的,每次点击按钮 @reddy 我的错,我在评论中提到使用 PureComponent 但我在编写代码时使用了 React.Component。我现在已经更新了代码。我希望现在可以使用:/ 还是一样,是不是因为我的 btnDisabled 状态是一个数组?【参考方案2】:您的按钮正在重新渲染,因为它们的道具正在改变。
通过将Button
定义移到渲染函数之外,您可以像这样实现:
const Button = memo(props =>
console.log('I am from button')
const btnIndex, onClick, disabled = props
return (
<button
onClick=() => onClick(btnIndex)
value=btnIndex
disabled=disabled
>
click me
</button>
)
)
function App()
const initialBtnDisabled = [
false,
false,
false,
false,
false,
false,
false,
false,
]
const [btnDisabled, setBtnDisabled] = useState(initialBtnDisabled)
const btnDisabledRef = useRef(btnDisabled)
btnDisabledRef.current = btnDisabled
const onClick = useCallback(btnIndex =>
let btnDisabledcopy = [...btnDisabledRef.current]
btnDisabledcopy[btnIndex] = true
setBtnDisabled(btnDisabledcopy)
, [])
const btnArr = [1, 2, 3, 4, 5, 6, 7, 8]
const btnFields = btnArr.map((item, index) => (
<td key=index>
<Button
btnIndex=index
onClick=onClick
disabled=btnDisabled[index]
/>
</td>
))
return <tr>btnFields</tr>
const rootElement = document.getElementById('root')
ReactDOM.render(<App />, rootElement)
注意使用useRef
来跟踪状态的当前值。这允许我们将[]
指定为依赖项
【讨论】:
以上是关于更改数组中的一个状态会导致在 React Hooks 中重新渲染整个循环生成的自定义组件的主要内容,如果未能解决你的问题,请参考以下文章
React Typescript 尝试更改数组对象的状态导致错误
如何在 React 中使用 useState Hook 更改/添加数组的某一行的值