背景
我正在开发一个流星应用程序,它使用ReactJS作为渲染库。
目前,在更新数据时,即使父组件正在访问更新的数据&应该将其传递给子组件,我也无法让子组件重新呈现。
父组件是数据表。子组件是一个单击可编辑的日期字段。
它的工作方式(理论上):父组件将date的现有数据作为道具传递给子组件。子组件获取现有的props数据,处理它并使用它设置一些状态,然后有两个选项:
我在表中每行使用子组件两次,每次使用它时,它都需要访问数据库中最新的日期数据。因此,如果数据在一个字段中发生更改,则第二个字段应反映该更改。
Problem
第二个字段不会反映数据库中的更改,除非我手动刷新页面并强制使子组件使用新数据呈现。编辑后的字段反映的是数据的变化,因为它反映的是状态中存储的内容。
在阅读React文档之后,我确信问题是因为日期是作为一个道具传入的,然后作为一个状态被处理--并且因为组件不会从道具更改中重新呈现。
我的问题
我该怎么做才能解决这个问题?
我对文档所做的所有阅读都强烈建议远离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
)
}
}
(如果这段代码/我的解释很粗糙,那是因为我仍然是一个相当初级/低级的开发人员。我没有接受过正式的培训,所以我在工作中学习,同时开发了一个相当困难的应用程序。作为一个单独的开发人员。说来话长。请温文点!)
发布于 2018-10-11 07:54:52
React文档中有一节介绍了constructor()
的最佳实践用法。阅读这篇文章,密切关注黄色突出显示的"Note“部分,应该会阐明您遇到的确切问题。
本质上,constructor()
只运行一次,最常用于初始化内部/本地状态(或绑定方法)。这意味着,当为该子组件调用时,该子组件将使用selected
prop 中的值来设置constructor()
和date1
。在调用constructor()
时,无论selected
的值是什么,都将被设置为子对象的状态,即使该值继续更改,该值也将保持不变。
因此,对传递给子组件的selected
属性的任何后续更新都不会反映在该组件的内部状态中,这意味着将不会重新呈现该组件。您需要在子组件中的其他位置使用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组件模式,那么很好地利用React生命周期方法将真正帮助您走出这一步。我不能强烈建议你学习the React component lifecyle。随着您继续使用React,它在这样的情况下将变得至关重要。componentDidMount()
和componentDidUpdate()
是很好的起点。
希望这能有所帮助。让我们知道结果如何。
https://stackoverflow.com/questions/52749644
复制相似问题