How properly refresh moment.from(). I tried set setInterval(this.renderReminders(), 1000) in componentDidMount, but doesn't work, popup error. How solve this issue?
class App extends Component {
renderReminders() {
const { reminders } = this.props;
return (
<ListGroup>
{
reminders.map(reminder => {
return (
<ListGroupItem key={reminder.id}>
<div>{moment(reminder.dueDate, 'DD-MM-YYYY HH:mm').fromNow()}</div>
</ListGroupItem>
) // return
}) // reminders.map
}
</ListGroup>
) // return
} // renderReminders()
render() {
return (
<div className="container">
{ this.renderReminders() }
</div>
) // return
} // render
} // App
How properly refresh moment.from(). I tried set setInterval(this.renderReminders(), 1000) in componentDidMount, but doesn't work, popup error. How solve this issue?
class App extends Component {
renderReminders() {
const { reminders } = this.props;
return (
<ListGroup>
{
reminders.map(reminder => {
return (
<ListGroupItem key={reminder.id}>
<div>{moment(reminder.dueDate, 'DD-MM-YYYY HH:mm').fromNow()}</div>
</ListGroupItem>
) // return
}) // reminders.map
}
</ListGroup>
) // return
} // renderReminders()
render() {
return (
<div className="container">
{ this.renderReminders() }
</div>
) // return
} // render
} // App
Share
Improve this question
asked Jul 2, 2017 at 12:23
Rami ChasygovRami Chasygov
2,7849 gold badges26 silver badges39 bronze badges
2
- What error did you get when you put it in componentDidMount? – Khauri Commented Jul 2, 2017 at 12:27
- See if this similar post with a solution helps: stackoverflow.com/questions/36299174/setinterval-in-a-react-app – terpinmd Commented Jul 2, 2017 at 12:56
6 Answers
Reset to default 8I know I am late to post this but it could help others who are new to this problem.
IT IS BETTER TO USE react-moment with ease
REQUIREMENTS; moment, react-moment
import React from 'react'
import Moment from 'react-moment'
const UpdatesTheTime = () => {
return (
<Moment interval={1000} fromNow>
{reminder.dueDate}
</Moment>
)
}
export default UpdatesTheTime
it will update every second as I set the interval to 1000
to see result watch it changes after 1 minute mark
I USE TIMESTAMP like this 1590115433736 for the time value and it works well
see https://openbase.io/js/react-moment for further info
there is parse or format that you can use for your time value.
Example < Moment parse="YYYY-MM-DD HH:mm" />
I'd say there's easily a couple ways to make timers in React.
One suggestion is to extrapolate Reminder into another react component.
Set the reminderTime in the new component's state and then create a method that usesthis.setState
to update the timer.
setState will automatically re-render your component if the state changes.
In componentWillMount you should use setInterval
to call a function that wil update the state. In componentWillUnmount you should get rid of the interval with clearInterval
.
I didn't test the below code so it's mostly just to get the idea.
class Reminder extends React.Component{
constructor(props){
super(props);
this.state = {
reminderTime : moment(this.props.dueDate, 'DD-MM-YYYY HH:mm').fromNow()},
}
}
componentDidMount(){
// add the interval
this.interval = setInterval(this.updateReminderTime.bind(this), 3000);
}
componentWillUnmount(){
// remove the interval listener
clearInterval(this.interval);
}
updateReminderTime(){
this.setState({
reminderTime : moment(this.props.dueDate, 'DD-MM-YYYY HH:mm').fromNow()}
}
render(){
return <div>{this.state.reminderTime }</div>
}
}
class App extends Component {
renderReminders() {
return (
const reminders = this.props.reminders;
<ListGroup>
{
reminders.map(reminder => {
return (
<ListGroupItem key={reminder.id}>
<Reminder dueDate={reminder.dueDate} />
</ListGroupItem>
) // return
}) // reminders.map
}
</ListGroup>
) // return
} // renderReminders()
render() {
return (
<div className="container">
{ this.renderReminders() }
</div>
) // return
} // render
} // App
Instead of using one component to render multiple timers, I think you should create one component to render 1 timer, and then re-use it for all your cases(pass the timer as prop to it).
Here is a basic example of one.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {date: moment().format('DD-MM-YYYY HH:mm').fromNow()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: moment().format('DD-MM-YYYY HH:mm').fromNow()
});
}
render() {
return (
<div>
date={this.state.date}
</div>
);
}
}
Now you only need to pass the initial date as prop, and re-use this component for all your timers.
Here is a component I made using hooks.
import moment from "moment";
import React, { useEffect, useState } from "react";
const formatter = (timestamp) => {
return moment.unix(timestamp).fromNow();
};
export default ({ timestamp, interval }) => {
const [timestampString, setTimestampString] = useState("");
useEffect(() => {
const timer = setInterval(
() => setTimestampString(formatter(timestamp)),
interval
);
setTimestampString(formatter(timestamp));
return () => clearInterval(timer);
}, []);
return timestampString;
};
It can be used as:
<ReactMoment timestamp={1597213985} interval={1000} />
It updates the moment time every 1 second.
const {ListGroup, ListGroupItem} = Reactstrap;
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
interval: null,
reminders: this.nextReminders(props.reminders),
};
this.refreshReminders = this.refreshReminders.bind(this);
this.nextReminders = this.nextReminders.bind(this);
}
componentDidMount() {
const interval = setInterval(this.refreshReminders, 1000);
this.setState({ interval });
}
componentWillUnmount() {
const { interval } = this.state;
clearInterval(interval);
}
refreshReminders() {
const { reminders } = this.props;
const nextReminders = this.nextReminders(reminders);
this.setState({ reminders: nextReminders });
console.log('refresh !');
}
nextReminders(reminders) {
return reminders.map(reminder => {
return {
...reminder,
render: moment(reminder.dueDate, 'DD-MM-YYYY HH:mm').fromNow()
};
});
}
renderReminders() {
const { reminders } = this.state;
return (
<ListGroup>
{
reminders.map(reminder => {
return (
<ListGroupItem key={reminder.id}>
<div>{reminder.render}</div>
</ListGroupItem>
) // return
}) // reminders.map
}
</ListGroup>
) // return
} // renderReminders()
render() {
return (
<div className="container">
{ this.renderReminders() }
</div>
) // return
} // render
} // App
const data = [
{id: 1, dueDate: '02-07-2017 15:34'},
{id: 2, dueDate: '02-07-2017 13:00'},
{id: 3, dueDate: '02-07-2017 14:00'},
];
ReactDOM.render(<App reminders={data} />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet"/>
<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>
<script src="https://unpkg.com/reactstrap/dist/reactstrap.min.js"></script>
<div id="app"></div>
You should keep time remaining in state, and use setInterval to periodically update (decrement) that part of the state. This state update will then in turn trigger render of your component.