[英]Why does Component re-renders on Click and state change?
Why does a whole component in react re-render when you change state in a onClick?为什么当您在 onClick 中更改 state 时,反应中的整个组件会重新呈现?
exmaple:https://codesandbox.io/s/vibrant-firefly-sgk5g?file=/src/App.js 示例:https://codesandbox.io/s/vibrant-firefly-sgk5g?file=/src/App.js
When you click on the numbers the whole components re-renders, and if you remove the setCount from the on click function it works just fine当您单击数字时,整个组件会重新呈现,并且如果您从单击 function 中删除 setCount,它就可以正常工作
The idea behind the component is to add a "Active" class to the number that you have clicked, and it updated a random counter, that counter prevents the addition the "active" class, since it re-renders the whole component该组件背后的想法是将“活动” class 添加到您单击的数字中,并且它更新了一个随机计数器,该计数器阻止添加“活动” class,因为它重新渲染了整个组件
EDIT: code here aswell编辑:这里也有代码
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;
It's the way react rerenders when a component state changes.这是当组件 state 发生变化时重新渲染的方式。 The state hook rerenders the whole component that it's in when the setState function is called which is the second element in the array that useState returns.
state 钩子在调用 setState function 时重新呈现它所在的整个组件,这是 useState 返回的数组中的第二个元素。
If you want to change the class of an element on click, you need to store it as a state.如果要在单击时更改元素的 class,则需要将其存储为 state。 In your code, the class of clicked span is updated on click, but right after that the component is rerendered and set to what the HandleHours returns.
在您的代码中,单击跨度的 class 会在单击时更新,但之后组件会重新呈现并设置为 HandleHours 返回的内容。
I would probalby have a state that keeps track which day is clicked and render that accordingly (not sure why you need the count, but I left it there):我很可能有一个 state 来跟踪点击了哪一天并相应地呈现(不知道为什么你需要计数,但我把它留在那里):
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;
The issue here isn't coming from the fact that the HandleHours components render but because it gets remounted everytime you change the state in the Hours component.这里的问题不是来自 HandleHours 组件呈现的事实,而是因为每次更改 Hours 组件中的 state 时都会重新安装它。
This happens because HandleHours
is defined as a component within Hours
component and everytime Hours
re-renders a new reference to HandleHours
is created which fools react into thinking that the component detached from DOM and a new component replaces it, since it essentialy works on reference.发生这种情况是因为
HandleHours
被定义为Hours
组件中的一个组件,并且每次Hours
重新呈现一个对HandleHours
的新引用时,都会创建一个傻瓜的反应,认为该组件与 DOM 分离并且一个新组件替换它,因为它本质上是在引用上工作的。
Now when you render HandleHours like现在,当您渲染 HandleHours 时
<div>
{ HandleHours () }
</div>
Suddenly HandleHours
turns from being a component to a function which returns JSX so this time when the Hours
component re-renders, even though the function reference to HandleHours
has changed.突然,
HandleHours
从一个组件变成了返回 JSX 的 function,所以这一次当Hours
组件重新渲染时,即使 function 对HandleHours
的引用已经改变。 It returns the JSX with a key prop on it, which remains the same and hence React treats it as a re-render and hour changes to DOM elements aren't lost它返回带有 key prop 的 JSX,它保持不变,因此 React 将其视为重新渲染,并且对 DOM 元素的小时更改不会丢失
Now there is a solution to the first approach too现在也有第一种方法的解决方案
All you need to do is to create a component HandleHours
outside of your Hours
component and render it by passing the required props like您需要做的就是在您的
Hours
组件之外创建一个组件HandleHours
并通过传递所需的道具来呈现它,例如
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;
When you do that the HandleHours
component isn't re-mounted on each rerender of Hours
component and it maintains the DOM elements correctly.当您这样做时,
HandleHours
组件不会重新安装在Hours
组件的每次重新渲染上,它会正确维护 DOM 元素。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.