Background
I am working on a Meteor app that uses ReactJS as the rendering library.
Currently, I'm having trouble with having a Child component re-render when data has been updated, even though the parent is accessing the updated data & supposedly passing it down to the child.
The Parent component is a Table of Data. The Child component is a Click-to-edit date field.
The way it (theoretically) works: Parent component passes the existing data for date into child component as a prop. Child component takes that existing props data, handles it & sets some states using it and then has 2 options:
- default: display data
- if user clicks on data field: change to input & allow user to select date (using react-datepicker), changing the state--when user clicks outside of field, triggers a return to display only & saves the updated data from state to database
I am using the child component twice per row in the table, and each time it is used, it needs access to the most current date data from the database. So if it the data is changed in one field, the second field should reflect that change.
Problem
The second field is not reflecting changes in the database unless I manually refresh the page and force the child component to render with the new data. The edited field is reflecting the data change, because it's reflecting what's stored in state.
After reading React documentation, I am sure the problem is because the date is coming in as a prop, then being handled as a state--and because the component isn't going to re-render from a prop change.
My Question
What do I do to fix this?
All of the reading I've done of the docs has strongly recommended staying away from things like forceUpdate() and getDerivedStateFromProps(), but as a result I'm not sure how to have data pass through the way that I want it to.
Thoughts?
My Code
I've abbreviated the code a little bit & removed variable names specific to my project, but I can provide more of the actual if it'll help. I think my question is more conceptual than it is straight up debugging.
Parent
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]} />
)
}
Child
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
)
}
}
(If this code/my explanation is rough, it's because I'm still a fairly beginner/low level developer. I don't have formal training, so I'm learning on the job while working on a pretty difficult app. As a solo developer. It's a long story. Please be gentle!)