我正在制作一个简单的从上到下的组件,我认为React仅在组件发生更改时才会重新渲染该组件。由于我的渲染中有条件绑定到状态,因此React是否应该仅在状态更改时才渲染它?取而代之的是,我看到它在每次滚动时都重新呈现。
此外,如果我将其保留原样,那么重新渲染有什么弊端吗?
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
);
};
};
答案 0 :(得分:4)
欢迎堆栈溢出:)
让我们仔细考虑一下您的代码。
在加载组件时,您会将侦听器附加到滚动事件:
componentDidMount() {
window.addEventListener('scroll', this.handleScroll);
}
当用户滚动时会触发handleScroll
。 handleScroll
设置组件的状态,无论三元条件是否解析为true或false:
handleScroll = () => {
this.setState({
shouldShowButton: window.scrollY > 250 ? true : false
});
}
每当我们使用setState
时,React就会触发render
。因此,render
每次滚动都会触发。
缺点-将任何内容附加到scroll
时应格外小心,因为它会影响性能。如果确实需要,可以考虑取消事件的弹跳。 (去抖动是限制函数可调用次数的技术。)
答案 1 :(得分:0)
之所以会发生这种情况,是因为每次触发滚动事件时都在调用handleScroll函数。要解决此问题,请仅在以下情况下使用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
);
};
};
答案 2 :(得分:0)
否,这是典型的组件。每次调用.setState
,更改props
或重新渲染父元素时,都会重新渲染(不是在DOM中而是在虚拟DOM中)。
仅举一个例子,父母重新渲染还可以激发孩子的重新渲染:
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);
在这里,您可以检查是否在调用父级.setState
的行中重新渲染了孩子。
但这并不是100%的性能问题。虚拟DOM比浏览器DOM快得多。
但是,如果要避免这种行为,可以使用React.PureComponent而不是React.Component,这样它将不会在父级更新时重新呈现。当.setState
实际上没有更改值时,PureComponent也可以处理大小写。
因此,重新渲染将更少。
官方文档足够好,但这里也是fine article at Medium