【问题标题】:Rerender moment.fromNow() in React在 React 中重新渲染 moment.fromNow()
【发布时间】:2017-12-05 20:22:20
【问题描述】:

如何正确刷新 moment.from()。我尝试在 componentDidMount 中设置 setInterval(this.renderReminders(), 1000),但不起作用,弹出错误。如何解决这个问题?

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

【问题讨论】:

标签: javascript reactjs redux


【解决方案1】:

我想说在 React 中有几种方法可以轻松地制作计时器。
一个建议是将提醒外推到另一个反应组件中。

在新组件的状态下设置reminderTime,然后创建一个使用this.setState的方法来更新定时器。

如果状态改变,setState 会自动重新渲染你的组件。

在 componentWillMount 中,您应该使用 setInterval 来调用将更新状态的函数。在 componentWillUnmount 中你应该去掉clearInterval 的间隔。

我没有测试下面的代码,所以主要是为了得到这个想法。

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

【讨论】:

  • 我可以问一下吗?为什么你使用 ... bind(this) ... 我读了一百遍(有上下文的东西)虽然我不能正确理解它
  • @RamzanChasygov,如果您想在函数调用中附加某个上下文(数据所在的位置),您可以使用 bind(也有 call() 和 apply())。当涉及到 React 时,尤其是在类组件中,函数定义和调用可以在不同的地方(即在类中定义和从渲染调用)绑定变得很重要。有一个相同的官方文档reactjs.org/docs/…
【解决方案2】:

我认为您应该创建一个组件来渲染 1 个计时器,而不是使用一个组件来呈现多个计时器,然后在所有情况下重新使用它(将计时器作为道具传递给它)。

这是一个基本的例子。

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>
    );
  }
}

现在您只需将初始日期作为道具传递,并为所有计时器重用此组件。

【讨论】:

    【解决方案3】:

    我知道我迟到了,但它可以帮助其他刚接触这个问题的人。

    最好轻松使用 react-moment

    要求;时刻,反应时刻

    import React from 'react'
    import Moment from 'react-moment'
    
    const UpdatesTheTime = () => {
        return (
            <Moment interval={1000} fromNow>
                {reminder.dueDate}
            </Moment>
        )
    }
    
    export default UpdatesTheTime
    

    当我将间隔设置为 1000 时,它将每秒更新一次

    查看结果,观察 1 分钟后的变化

    我使用 TIMESTAMP 像 1590115433736 这样的时间值,效果很好

    更多信息请见https://openbase.io/js/react-moment

    您可以将 parseformat 用于您的时间价值。

    示例

    【讨论】:

      【解决方案4】:

      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>

      【讨论】:

        【解决方案5】:

        这是我使用钩子制作的一个组件。

        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;
        };
        
        

        它可以用作:

        <ReactMoment timestamp={1597213985} interval={1000} />
        

        它每 1 秒更新一次时刻。

        【讨论】:

          【解决方案6】:

          您应该保持状态的剩余时间,并使用 setInterval 定期更新(递减)该部分状态。然后,此状态更新将依次触发您的组件的渲染。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-12-30
            • 2021-06-07
            • 2021-12-29
            • 1970-01-01
            • 1970-01-01
            • 2021-06-03
            • 2020-08-31
            • 2021-12-27
            相关资源
            最近更新 更多