Reputation: 177
I'm trying to do a simple greeting text in react, but it's not working! There's no error complaining in the console, in fact it simply ignored everything in the
componentDidUpdate
and only showed the original dayPeriod text 'morning' in the **this,state**
. The code is as below:
class MainContent extends Component {
constructor(props) {
super(props)
dayPeriod: 'morning'
}
}
}
componentDidUpdate(preProps, preState) {
//handleDayPeriod
let hour = new Date().getHours()
let newDayPeriod = hour < 12 ? 'Morning' : hour >= 12 && hour < 17? 'Afternoon' : 'Evening'
if (preState.dayPeriod && preState.dayPeriod !== newDayPeriod) {
this.setState({
dayPeriod: newDayPeriod
})
}
}
render() {
return (
<div className='greeting'>Good {this.state.dayPeriod}!</div>
)
}
Can anyone help see what's the problem?
Upvotes: 0
Views: 172
Reputation: 1160
componentDidUpdate does not fire on the very first render. So if you want to do the things like that, it is better to use componentDidMount to run the function checking from time to time if day period is changed or not.
class MainContent extends Component {
constructor(props) {
super(props)
this.state = {
itemsReversed: ['Event 1', 'Event 2', 'Event 3', 'Event 4', 'Event 5'].reverse(),
allChecked: false,
isChecked: true,
dayPeriod: 'morning',
intervalId: null
}
this.btnSelectAll = React.createRef()
}
// when component is created we start the function checking if the greeting needs update
// the interval id also is saved into state for cleaning later
// now it works every 1sec but for practical purpose it s better to set up as 60000 (1min)
componentDidMount(){
this.setState({intervalId: setInterval(this.changeDayPeriod, 1000)})
}
// this section clear up the timer to avoid memory leak:
componentWillUnmount() {
clearInterval(this.state.intervalId)
}
// this function is yours but now it compares current time value with the stored one, not prev and next ones:
changeDayPeriod = () => {
const hour = new Date().getHours()
const newDayPeriod = hour < 12 ? 'Morning' : hour >= 12 && hour < 17? 'Afternoon' : 'Evening'
if (this.state.dayPeriod !== newDayPeriod) {
this.setState({
dayPeriod: newDayPeriod
})
}
}
render() {
return (
<div className='greeting'>Good {this.state.dayPeriod}!</div>
)
}
}
Upvotes: 0
Reputation: 84947
componentDidUpdate
is the wrong place to be putting this code. componentDidUpdate
gets called when new props get passed into the component, or when the component's state changes. If you just want to set the initial value of the state, put the code into your constructor:
constructor(props) {
super(props)
let hour = new Date().getHours()
let newDayPeriod = hour < 12 ? 'Morning' : hour >= 12 && hour < 17 ? 'Afternoon' : 'Evening'
this.state = {
dayPeriod: newDayPeriod
}
}
Note that as time passes, this is not going to update. If you need it to do so, you'll need to add some extra code to update the state.
In the following code, componentDidMount
means this code will get run immediately after the component is mounted (ie, after it's created for the first time). componentWillUnmount
happens right before the component is about to be destroyed.
class MainContent extends Component {
constructor () {
// same as above
}
componentDidMount() {
this.intervalId = setInterval(() => {
let hour = new Date().getHours()
let newDayPeriod = hour < 12 ? 'Morning' : hour >= 12 && hour < 17 ? 'Afternoon' : 'Evening'
if (newDayPeriod !== this.state.dayPeriod) {
this.setState({ dayPeriod: newDayPeriod })
}
}, 60000); // Every 10 minutes. I chose this pretty arbitrarily
}
componentWillUnmount() {
clearInterval(this.intervalId);
}
}
The above code just blindly tries to update every 10 minutes. That's the simplest approach, and should be fine for many cases. But if you wanted to be more precise, then instead of having a repeating interval, you could calculate a timeout that you know will go off right when we roll to a new day period.
Upvotes: 1