[英]Why is React rendering my component over and over with an unchanged state?
I'm making a simple scroll-to-top component and I thought that React will only re-render a component if something in it changes. 我正在制作一个简单的从上到下的组件,我认为React仅在组件发生更改时才会重新渲染该组件。 Since I have a conditional tied to state in my render, shouldn't React only render it if the state changes?
由于我的渲染中有条件绑定到状态,因此React是否应该仅在状态更改时才渲染它? Instead, I'm seeing it re-render with every little scroll.
取而代之的是,我看到它随着每个小滚动都重新呈现。
Also, if I left it as-is, are there any downsides to it re-rendering so much? 另外,如果我原样保留它,那么重新渲染是否有任何负面影响?
import React from 'react';
import './scroll-to-top.css';
export default class extends React.Component {
state = {
shouldShowButton: false
}
componentDidMount() {
window.addEventListener('scroll', this.handleScroll);
}
componentWillUnmount() {
window.removeEventListener('scroll', this.handleScroll);
}
handleScroll = () => {
this.setState({
shouldShowButton: window.scrollY > 250 ? true : false
});
}
render () {
{console.log("i have rendered!")}
return (
this.state.shouldShowButton ? <a className="scroll-to-top" href="#">Return to Top</a> : null
);
};
};
Welcome to Stack Overflow :) 欢迎使用Stack Overflow :)
Let's think through your code. 让我们仔细考虑一下您的代码。
When the component loads, you're attaching a listener to the scroll event: 加载组件时,您会将侦听器附加到滚动事件:
componentDidMount() {
window.addEventListener('scroll', this.handleScroll);
}
This fires handleScroll
when the user scrolls. 用户滚动时将触发
handleScroll
。 handleScroll
sets the state of the component, regardless of whether or not the ternary condition resolves as true or false: handleScroll
设置组件的状态,而不考虑三元条件是否解析为true或false:
handleScroll = () => {
this.setState({
shouldShowButton: window.scrollY > 250 ? true : false
});
}
Whenever we use setState
, React triggers render
. 每当我们使用
setState
,React都会触发render
。 Hence, render
is triggering with every little scroll. 因此,
render
会在每次滚动时触发。
Downsides - you should be really careful of attaching anything to scroll
, as it can affect performance. 缺点-您应该非常小心地附加任何要
scroll
,因为它会影响性能。 You might consider debouncing the event if you really, really need to do so. 如果确实需要,可以考虑取消事件的弹跳。 (Where debouncing is the technique of rate-limiting how many times a function can be called.)
(去抖动是限制函数可调用次数的技术。)
This happens, because you are calling handleScroll function every time scroll event is fired. 发生这种情况的原因是,每次滚动事件触发时,您都在调用handleScroll函数。 To fix this, setState only in condition:
要解决此问题,请仅在以下情况下使用setState:
import React from 'react';
import './scroll-to-top.css';
export default class extends React.Component {
state = {
shouldShowButton: false
}
componentDidMount() {
window.addEventListener('scroll', this.handleScroll);
}
componentWillUnmount() {
window.removeEventListener('scroll', this.handleScroll);
}
handleScroll = () => {
const {shouldShowButton} = this.state;
if (!shouldShowButton && window.scrollY > 250) {
this.setState({
shouldShowButton: true
});
} else if (shouldShowButton && window.scrollY <= 250) {
this.setState({
shouldShowButton: false
});
}
}
render () {
{console.log("i have rendered!")}
return (
this.state.shouldShowButton ? <a className="scroll-to-top" href="#">Return to Top</a> : null
);
};
};
No, it's typical for Component. 不,这是典型的组件。 It's re-rendered(not in DOM but in virtual DOM) each time
.setState
is called, props
are changes or parent element is re-rendered . 每次调用
.setState
,更改props
或重新渲染父元素时,都会重新渲染(不是在DOM中,而是在虚拟DOM中)。 Just an example how re-rendering parent also fires re-rendering for child: 仅举一个例子,父母重新渲染还可以激发孩子的重新渲染:
import React from "react";
import ReactDOM from "react-dom";
class Child extends React.Component {
render() {
console.log('child re-rendered');
return 'test';
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {a: 1};
setInterval(() => this.setState(oldState => ({...oldState, a: oldState.a + 1})), 1000);
}
render() {
return (
<div className="App">
<Child />
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Here you can check that child is re-rendered in the line as parent's .setState
is called. 在这里,您可以检查是否在调用父级的
.setState
的行中重新渲染了子.setState
。
But it is not 100% to be issue for performance. 但这并不是100%的性能问题。 Virtual DOM is much faster than browser DOM.
虚拟DOM比浏览器DOM快得多。
But if you want to avoid such a behavior you may use React.PureComponent instead of React.Component and then it will not be re-rendered on parent's update. 但是,如果要避免这种行为,可以使用React.PureComponent而不是React.Component,这样它将不会在父级更新时重新呈现。 Also PureComponent handles case when
.setState
does not actually changes value. 当
.setState
实际上不更改值时, .setState
也可以处理这种情况。 So there will be less re-rendering. 因此,重新渲染将更少。
Official docs are good enough but here is also fine article at Medium 官方文档已经足够好了,但是在Medium上也不错
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.