为啥组件在单击和状态更改时会重新渲染?
Posted
技术标签:
【中文标题】为啥组件在单击和状态更改时会重新渲染?【英文标题】:Why does Component re-renders on Click and state change?为什么组件在单击和状态更改时会重新渲染? 【发布时间】:2020-08-14 15:04:34 【问题描述】:当你在 onClick 中改变状态时,为什么整个 react 组件会重新渲染?
例如:https://codesandbox.io/s/vibrant-firefly-sgk5g?file=/src/App.js
当您单击数字时,整个组件会重新渲染,如果您从 on click 函数中删除 setCount,它就可以正常工作
组件背后的想法是为您单击的数字添加一个“活动”类,它更新了一个随机计数器,该计数器阻止添加“活动”类,因为它重新呈现整个组件
编辑:这里也有代码
import React, useState from "react";
const Hours = () =>
const days = [1, 2, 3, 4, 5, 6];
const [count, setCount] = useState(1);
const TestClick = (e, item) =>
setCount(count + 1);
e.currentTarget.className = "active";
;
const HandleHours = () =>
let block = <span />;
if (days)
block = days.map((hour, index) =>
return (
<span
style= display: "block"
onClick=e =>
TestClick(e, hour);
className=`col-md-4` key=index>
hour
</span>
);
);
return block;
;
return (
<div>
<HandleHours />
</div>
);
;
export default Hours;
【问题讨论】:
您在寻找不同的答案吗? 【参考方案1】:这里的问题不是来自 HandleHours 组件呈现的事实,而是因为每次更改 Hours 组件中的状态时它都会重新安装。
发生这种情况是因为HandleHours
被定义为Hours
组件中的一个组件,并且每次Hours
重新渲染一个对HandleHours
的新引用时,傻瓜的反应是认为该组件与DOM 分离并且一个新的组件替换它,因为它本质上是在参考上工作的。
现在当你渲染 HandleHours 时像
<div>
HandleHours ()
</div>
HandleHours
突然从一个组件变成了一个返回 JSX 的函数,所以这次 Hours
组件重新渲染,即使对 HandleHours
的函数引用已经改变。它返回带有 key prop 的 JSX,它保持不变,因此 React 将其视为重新渲染,并且对 DOM 元素的小时更改不会丢失
现在第一种方法也有解决方案
您需要做的就是在您的 Hours
组件之外创建一个组件 HandleHours
并通过传递所需的 props 来呈现它
import React, useState from "react";
import "./styles.css";
const HandleHours = ( days, TestClick ) =>
let block = <span />;
if (days)
block = days.map((hour, index) =>
return (
<span
style= display: "block"
onClick=e =>
TestClick(e, hour);
className=`col-md-4`
key=index
>
hour
</span>
);
);
return block;
;
const days = [1, 2, 3, 4, 5, 6];
const Hours = () =>
const [count, setCount] = useState(1);
const TestClick = (e, item) =>
setCount(count + 1);
console.log("TestClick");
e.currentTarget.className = "active";
;
return (
<div>
<HandleHours days=days TestClick=TestClick />
</div>
);
;
export default Hours;
当您这样做时,HandleHours
组件不会重新安装在 Hours
组件的每次重新渲染上,它会正确维护 DOM 元素。
Here is a working demo for the second approach
【讨论】:
【参考方案2】:这是当组件状态改变时 react 重新渲染的方式。状态钩子会在调用 setState 函数时重新呈现它所在的整个组件,这是 useState 返回的数组中的第二个元素。
如果你想在点击时改变一个元素的类,你需要把它存储为一个状态。在您的代码中,clicked span 的类在单击时更新,但在此之后组件会重新呈现并设置为 HandleHours 返回的内容。
我可能会有一个状态来跟踪点击了哪一天并相应地呈现(不知道为什么需要计数,但我把它留在那里):
import React, useState from "react";
const Hours = () =>
const days = [1, 2, 3, 4, 5, 6];
const [count, setCount] = useState(1);
const [clickedDays, setClickedDays] = useState([]); // Added clickedDays state
const TestClick = (e, item, isDayClicked) =>
setCount(count + 1);
if (!isDayClicked) // Setting clicked days if they are not in the array yet
setClickedDays([...clickedDays, item])
;
const HandleHours = () =>
let block = <span />;
if (days)
block = days.map((hour, index) =>
const isDayClicked = clickedDays.includes(hour);
return (
<span
style= display: "block"
onClick=e =>
TestClick(e, hour, isDayClicked);
className=isDayClicked ? 'active' : 'col-md-4' // Setting different class depending on state
key=index
>
hour
</span>
);
);
return block;
;
return (
<div>
<HandleHours />
</div>
);
;
export default Hours;
【讨论】:
计数是为了显示我面临的问题,但我发现了问题,看看我的答案以上是关于为啥组件在单击和状态更改时会重新渲染?的主要内容,如果未能解决你的问题,请参考以下文章
更改数组中的一个状态会导致在 React Hooks 中重新渲染整个循环生成的自定义组件
我的 Redux 状态发生了变化,为啥 React 没有触发重新渲染?