![](/img/trans.png)
[英]How can I avoid re-rendering of component due to props change, to fix performance problems
[英]Ways to fix a child component that is not re-rendering (due to change in data being passed in as props, not state)?
背景
我正在使用一个使用ReactJS作为渲染库的Meteor应用程序。
目前,我在更新数据时重新渲染子组件时遇到问题,即使父级正在访问更新的数据并且据称将其传递给子级。
Parent组件是一个数据表。 子组件是单击编辑日期字段。
它(理论上)的工作方式 :父组件将日期的现有数据作为prop传递给子组件。 子组件获取现有的道具数据,处理它并使用它设置一些状态,然后有2个选项:
我在表中每行使用子组件两次,每次使用它时,它需要访问数据库中的最新日期数据。 因此,如果数据在一个字段中更改,则第二个字段应反映该更改。
问题
除非我手动刷新页面并强制子组件使用新数据进行渲染,否则第二个字段不会反映数据库中的更改。 编辑的字段被反映数据的变化,因为它反映了什么是存储在状态。
阅读完React文档之后,我确定问题是因为日期是作为一个prop进入,然后作为一个状态处理 - 并且因为该组件不会从prop更改中重新呈现。
我的问题
我该怎么做才能解决这个问题?
我对文档所做的所有阅读强烈建议远离诸如forceUpdate()和getDerivedStateFromProps()之类的东西,但结果我不确定如何通过我想要的方式传递数据。
思考?
我的守则
我已经将代码缩减了一点并删除了特定于我的项目的变量名称,但是如果它有帮助我可以提供更多的实际代码。 我认为我的问题比直接调试更具概念性。
亲
ParentComponent () {
//Date comes as a prop from database subscription
var date1 = this.props.dates.date1
var date2 = this.props.dates.date2
return(
<ChildComponent
id='handle-date-1'
selected={[date1, date2]} />
<ChildComponent
id='handle-date-2'
selected={[date1, date2]} />
)
}
儿童
ChildComponent() {
constructor(props) {
super(props);
this.state = {
date1: this.props.selected[0],
date2: this.props.selected[1],
field: false,
};
}
handleDatePick() {
//Handles the event listeners for clicks in/out of the div, handles calling Meteor to update database.
}
renderDate1() {
return(
<div>
{this.state.field == false &&
<p onClick={this.handleClick}>{formatDate(this.state.date1)}</p>}
{this.state.field == true &&
<DatePicker
selected={this.state.date1}
startDate={this.state.date1}
onChange={this.handleDatePick}
/>
}
</div>
)
}
renderDate2() {
return(
<div>
{this.state.field == false &&
<p onClick={this.handleClick}>{formatDate(this.state.date2)}</p>}
{this.state.field == true &&
<DatePicker
selected={this.state.date2}
startDate={this.state.date2}
onChange={this.handleDatePick}
/>
}
</div>
)
}
render() {
return(
//conditionally calls renderDate1 OR renderDate2
)
}
}
(如果这个代码/我的解释很粗糙,那是因为我还是一个相当初学者/低级别的开发人员。我没有接受过正式培训,所以我在学习一个非常困难的应用程序时正在学习这个工作。独唱开发者。这是一个很长的故事。请温柔!)
React文档有一节关于constructor()
最佳实践用法。 阅读,密切注意黄色突出显示的“注意”部分,应该说明你遇到的确切问题。
本质上, constructor()
只运行一次,最常用于初始化内部/本地状态(或绑定方法)。 这意味着你的子组件设置date1
和date2
从您的价值观selected
道具时, 一次 constructor()
被调用那个孩子。 无论selected
的值是什么,当constructor()
被调用时将被设置为子状态,并且即使值继续改变也将保持不变。
因此,传递给子组件的selected
prop的任何连续更新都不会反映在该组件的内部状态中,这意味着不会重新呈现该组件。 您需要在子组件的其他位置使用React的setState()
方法来正确更新该子级的状态并触发重新呈现。
使用React生命周期方法的组合来正确更新子组件是可行的方法。 下面的代码片段为您提供了有关在componentDidMount()
和componentDidUpdate()
实现更改的主要想法
class Child extends React.Component { constructor(props) { super(props); this.state = { date1: 0, date2: 0, }; } /* Any time the child mounts to the DOM, you can use the method below to set your state using the current value of your selected prop from the parent component... */ componentDidMount() { this.setState({ date1: this.props.selected[0], date2: this.props.selected[1] }); } /* When the child receives an update from its parent, in this case a new date selection, and should re-render based on that update, use the method below to make a comparison of your selected prop and then call setState again... */ componentDidUpdate(prevProps) { if (prevProps.selected !== this.props.selected) { this.setState({ date1: this.props.selected[0], date2: this.props.selected[1] }); } } render() { const { date1, date2 } = this.state; return ( <div style={{ border: `4px dotted red`, margin: 8, padding: 4 }}> <h1 style={{ fontWeight: 'bold' }}>Child</h1> <h2>The value of date1 is {date1}</h2> <h2>The value of date2 is {date2}</h2> </div> ); } } class Parent extends React.Component { constructor(props) { super(props); this.state = { valOne: 0, valTwo: 0 }; } incrementOne = () => { this.setState(prevState => ({ valOne: (prevState.valOne += 1) })); }; incrementTwo = () => { this.setState(prevState => ({ valTwo: (prevState.valTwo += 1) })); }; render() { const { valOne, valTwo } = this.state; return ( <div style={{ border: `4px solid blue`, margin: 8, padding: 4 }}> <h1 style={{ fontWeight: 'bold', fontSize: 18 }}>Parent</h1> <button onClick={() => this.incrementOne()}>Increment date1</button> <button onClick={() => this.incrementTwo()}>Increment date2</button> <Child selected={[valOne, valTwo]} /> </div> ); } } ReactDOM.render(<Parent />, document.querySelector('#app'));
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> <div id="app"></div>
由于您正在为您的孩子使用React Component模式,因此充分利用React生命周期方法将真正帮助您。 我不能强烈建议你学习React组件的生命周期 。 当你继续使用React时,在这种情况下它将变得至关重要。 componentDidMount()
和componentDidUpdate()
是很好的起点。
希望这会有所帮助。 让我们知道结果如何。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.