问题
Am a bit new to React and wrote this code below. The component below is for rendering a Time and Date Picker for a tale. The time and date pickers only render for those social media where the tale is scheduled to appear.
class TaleScheduler extends Component {
constructor(props) {
super(props);
this.state = {
returnData: {},
totalNeeded: numberOfChannels(this.props.data)
};
}
setSchedule = (date, channel) => {
const returnData = update(this.state.returnData, {
$merge: {channel: date}
})
this.setState({returnData: returnData})
const { data, ScheduleTale } = this.props
if (Object.values(this.state.returnData).length === this.state.totalNeeded) {
FireAction(this.state.returnData, data.id)
}
}
render() {
const { data } = this.props
return (
<div style={{"display": "inline-block"}}>
{data.showOnFacebook ? (<DateTimePicker data={data} image={facebook} setSchedule={this.setSchedule} />) : null}
{data.showOnTwitter? (<DateTimePicker data={data} image={instagram} setSchedule={this.setSchedule} />) : null}
{data.showOnInstagram ? (<DateTimePicker data={data} image={twitter} setSchedule={this.setSchedule} />) : null}
{data.showOnApp ? (<DateTimePicker data={data} image={app} setSchedule={this.setSchedule} />) : null}
<FlatButton label="Schedule" onClick={this.setSchedule} />
</div>
)
}
}
This renders a set of time and date pickers based on where the tale is to be displayed. Below is the component that is being displayed
class DateTimePicker extends Component {
constructor(props) {
super(props);
this.state = {
date: null,
time: null
};
}
handleDateInput = (event, date) => {
this.setState({
date: date
})
}
handleTimeInput = (event, time) => {
this.setState({
time: time
})
}
componentDidUpdate(prevProps, prevState) {
const {setSchedule, channel} = this.props
if (this.state.date && this.state.time) {
setSchedule(concatenateDateAndTime(this.state.date, this.state.time), channel)
}
}
render() {
return (
<List>
<ListItem
leftAvatar={
<img src={this.props.image} style={styles.scheduledChannelImgStyle} />
}>
</ListItem>
<ListItem>
<DatePicker onChange={this.handleDateInput} />
</ListItem>
<ListItem>
<TimePicker onChange={this.handleTimeInput} />
</ListItem>
</List>
)
}
}
On selecting both the date and the time above. The entire page locks into an endless loop that caused the page to freeze. I am sure the functions are being calling each other in loop. But I do not know enough about React rendering to be able to figure out exactly why.
回答1:
In the componentDidUpdate
check for the previous date and time state values
before calling the function otherwise it will be called whenever the date and time are defined and the component is updating which it will do whenever you call the setSchedule
function as it updates the state and parent which inturn leads to updated props being passed down to the child component.
Try
componentDidUpdate(prevProps, prevState) {
const {setSchedule, channel} = this.props
if(prevState.date !== this.state.data || prevState.time !== this.state.time) {
if (this.state.date && this.state.time) {
setSchedule(concatenateDateAndTime(this.state.date, this.state.time), channel)
}
}
}
To confirm that any update in the parent component, the child components componentDidUpdate
is called, have a look at this snippet
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
clicked: false
}
}
render() {
return (
<div>
<Child />
<button onClick={() => this.setState((prevState) => ({clicked: !prevState.clicked}))} > Toggle</button>
</div>
)
}
}
class Child extends React.Component {
componentDidUpdate(prevProps, prevState) {
console.log('update in child called');
}
render() {
return (
<div>
Hello Child
</div>
)
}
}
ReactDOM.render(<Parent/>, document.getElementById('app'));
<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>
回答2:
The reason is you are calling method setSchedule
inside componentDidUpdate
lifecycle method. setSchedule
method is calling setState()
. This resulting in a call to componentDidUpdate
which subsequently calls setState
again. you are creating an infinite loop because there's no break condition. you can call setState inside componentWillReceiveProps
instead of componentDidUpdate
.
componentDidUpdate(prevProps, prevState) {
const {setSchedule, channel} = this.props
if (this.state.date && this.state.time) {
setSchedule(concatenateDateAndTime(this.state.date, this.state.time), channel)//Calling method that calls setstate.
}
}
来源:https://stackoverflow.com/questions/44713614/react-code-locking-in-endless-loop-no-while-loops-involved