javascript - React 更改组件顺序不会触发重新渲染

标签 javascript reactjs heroku ecmascript-6

我正在设计一个系统来显示我的 Heroku 应用程序何时更新。我遇到的问题是父组件 (Herokus) 决定了顺序,但我希望它们根据更新时间从最近的开始进行排序。我能够通过将日期从 Heroku 组件传递回父 Herokus 组件来实现这一点。我尝试添加一个显示排序顺序的 console.log(this.state.apps),但这并没有被呈现的组件反射(reflect)出来。我的猜测是 React 没有将更改的组件顺序视为更新 View 的原因 - 但老实说我不知道​​。任何帮助表示赞赏。文件如下。抱歉,我的代码很乱,我重写了三遍试图解决这个问题。

Herokus 组件:

import React from 'react';
import Heroku from './Heroku';

export default class Herokus extends React.Component {
  constructor(props) {
    super(props);

    var apps = [
      'example-heroku-app'
    ]

    this.state = {
      apps: apps.map((h) => {
        return {
          app: h,
          updatedAt: new Date()
        };
      })
    }
  }

  sortApps() {
    var sorted = this.state.apps.sort((a, b) => {
      return a.updatedAt < b.updatedAt;
    });
    this.setState({
      apps: sorted
    });
  }

  updateParrent(data){
    var apps = this.state.apps;
    apps.find(x => x.app === data.app).updatedAt = data.updatedAt;
    this.setState({
      apps: apps
    });
    this.sortApps();
    this.forceUpdate();
  }

  render() {
    var s = this;

    return (
      <div>
        {s.state.apps.map((app, i) => {
          return (
            <Heroku app={app.app} compact key={`heroku-${i}`} updateParrent={s.updateParrent.bind(s)}/>
          );
        })}
      </div>
    );
  }
}

Heroku 组件:

import React from 'react';

export default class Ping extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
        app: props.app,
      updatedAt: new Date()
    };
  }

  componentDidMount() {
    var s = this;
    axios.get(`/api/heroku/app/${s.props.app}`, {
        timeout: 20000,
    })
    .then(res => {
        var data = res.data;
      s.setState({
        app: data.app.name,
        updatedAt: new Date(data.app['updated_at'])
      });
      s.props.updateParrent(s.state);

      setInterval(() => {
        var updatedAt = new Date(s.state.updatedAt);
        s.setState({
          updatedAt: updatedAt
        });
      }, 1000);
    });
  }

  howLongAgo(date) {
    var ms = new Date() - date;
    var seconds = ms / 1000;
    var n = seconds;
    var suffix = '';

    // less than 1 minute
    if(seconds < 60){
      n = seconds;
      suffix = 'second' + (n > 1.5 ? 's' : '');
    }
    // less than 1 hour
    else if(seconds < 3600) {
      n = seconds / 60
      suffix = 'minute' + (n > 1.5 ? 's' : '');
    }
    // less than 1 day
    else if(seconds < 86400) {
      n = seconds / 3600;
      suffix = 'hour' + (n > 1.5 ? 's' : '');
    }
    // less than 1 week
    else if(seconds < 604800) {
      n = seconds / 86400;
      suffix = 'day' + (n > 1.5 ? 's' : '');
    }
    // more than 1 week
    else {
      n = seconds / 604800;
      suffix = 'week' + (n > 1.5 ? 's' : '');
    }

    return `${Math.round(n)} ${suffix} ago`;
  }

  render() {
    var s = this.state;
    var self = this;
    var output;

    // COMPACT VIEW
    if(this.props.compact){
      output = (
        <div className={'heroku heroku-compact'}>
            <h3>{s.app}</h3>
            <p>{self.howLongAgo(s.updatedAt)}</p>
            <div className='clearfix'></div>
        </div>
      )

    // FULL SIZE VIEW
    } else{
      output = ()
    }

    return output;
  }
}

最佳答案

问题似乎是顺序发生了变化,但由于键是基于 i 索引变量的,因此记录的列表仍然具有相同顺序的相同键。因此 React 看不出有什么不同。

例子:

未排序的应用程序 a、b 和 c

<div key="1"> //app b
<div key="2"> //app a
<div key="3"> //app c

已排序的应用

<div key="1"> //app a
<div key="2"> //app b
<div key="3"> //app c

应用程序现在的顺序是正确的,但父组件 Herokus 仍然以相同的顺序使用键 1、2 和 3 来显示它们。

解决方法: 将 key 更改为各个 Heroku 组件独有的内容,但与 updatedAt 不同的是将保持不变。在这种情况下,最合乎逻辑的选择是应用名称。

这可以在 Herokus 组件的渲染函数中实现,如下所示:

export default class Herokus extends React.Component {
  render() {
    var s = this;

    return (
      <div>
        {s.state.apps.map((app, i) => {
          return (
            <Heroku app={app.app} compact key={`heroku-${app.app}`} updateParrent={s.updateParrent.bind(s)}/>
          );
        })}
      </div>
    );
  }
}

关于javascript - React 更改组件顺序不会触发重新渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46959080/

相关文章:

javascript - 如何过滤javascript数组中的未定义值?

javascript - 如何将 Styled Component 样式应用于自定义 React 组件?

reactjs - react native : Uncaught (in promise) Error: DeltaPatcher should receive a base Bundle when being initialized

javascript - 如何在(protip)工具提示内容上注册 'click' 事件?

javascript - 三星智能电视地址 MAC

javascript - 未捕获的类型错误 : this. props.onDelete 不是函数 reactjs

ruby-on-rails - 在 Heroku 上启用 Ruby PostGIS 支持

ruby-on-rails - Heroku Puma Rails 4 : Getting R14 errors, 如何扩展我的服务器?

ruby-on-rails - Heroku 上出现 "invalid multibyte escape:/^\xFF\xFE/(SyntaxError)"错误

javascript - 如何在网站上使用各种字体