React函数正确初始化及组件滚动位置设置优化咨询
问题解答
1. React中正确初始化函数的方式
在React类组件里,初始化函数有两种常用且规范的方式:
方式一:类字段箭头函数(你当前使用的方式)
这种写法会自动把this绑定到组件实例上,代码简洁还不用手动处理this指向:
setScrollLeft = () => { // 函数逻辑 };
优点:省去构造函数里的绑定步骤,this指向始终稳定,用起来省心。
方式二:构造函数中手动绑定
如果不想用箭头函数,就得在constructor里通过bind把this绑定到函数上,不然调用时this容易丢失:
constructor(props) { super(props); this.setScrollLeft = this.setScrollLeft.bind(this); } setScrollLeft() { // 函数逻辑 }
要是换成函数组件的话,直接声明函数就行,还能根据需求用useCallback缓存函数,避免不必要的重渲染。
2. 优化滚动位置设置的方案
你的代码核心问题是在render里调用setScrollLeft——render的职责应该只是输出UI,不该放这种有副作用的操作,每次组件渲染都会执行这个方法,既不符合React的设计逻辑,还可能引发性能问题。下面是优化后的完整方案:
优化点说明:
- 把
render里的this.setScrollLeft()调用移走,改用生命周期方法处理滚动这种副作用 - 直接通过
ref.current访问DOM节点,不用额外存成实例属性this.element,更可靠 - 删掉
constructor里缓存props.data的代码,直接用this.props.data,保证数据和props同步 - 在
componentDidMount里初始化滚动,在componentDidUpdate里根据父组件的更新触发滚动
优化后的代码:
import React from 'react'; import { ScoreCell, getScoreTheme } from 'components/scores'; class LeaderboardPlayerResult extends React.Component { constructor(props) { super(props); this.containerWidth = 198; this.playerResultRef = React.createRef(); } componentDidMount() { this.setScrollLeft(); } componentDidUpdate(prevProps) { // 可以根据需求加判断条件,比如只有props变化时才触发滚动 // 这里默认父组件setState导致props更新时,重新设置滚动位置 this.setScrollLeft(); } setScrollLeft = () => { const element = this.playerResultRef.current; if (element) { element.scrollLeft = this.containerWidth; } }; playerResult = () => { const { data } = this.props; if (data.playOffHoles) { return data.playOffHoles.map((item, index) => ( <div className="leaderboard__player-result-row-wrapper" key={index}> <div className="leaderboard__player-result-row"> <div className="leaderboard__player-result-cell">{item.holeId}</div> </div> <div className="leaderboard__player-result-row"> <div className="leaderboard__player-result-cell">{item.holePar}</div> </div> <div className="leaderboard__player-result-row"> <div className="leaderboard__player-result-cell leaderboard__player-result-cell--score"> <ScoreCell childCss='tee-times-card__score' theme={getScoreTheme(item.playOffParScore)}> {item.playOffParScore} </ScoreCell> </div> </div> </div> )); } return null; // 没有数据时返回null,避免渲染undefined }; render() { console.log('LeaderboardPlayerResult render'); return ( <div className="leaderboard__player-result" ref={this.playerResultRef}> {this.playerResult()} </div> ); } }
额外建议:
如果只想在特定条件下触发滚动(比如只有playOffHoles数据变化时),可以在componentDidUpdate里加个判断:
componentDidUpdate(prevProps) { if (prevProps.data.playOffHoles !== this.props.data.playOffHoles) { this.setScrollLeft(); } }
这样能避免不必要的滚动操作,提升组件性能。
内容的提问来源于stack exchange,提问作者user11700058
相关产品推荐
相关产品推荐

