最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Rerender moment.fromNow() in React - Stack Overflow

programmeradmin1浏览0评论

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
Add a comment  | 

6 Answers 6

Reset to default 8

I 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.

发布评论

评论列表(0)

  1. 暂无评论