更新React列表而不重新呈现所述列表?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (58)

我试图弄清楚如何渲染一组div,而不是在添加新集合时重新渲染整个列表。

所以我有一个有状态的组件。在所述有状态组件内部,我有一个函数A,获取post id的列表,B,向每个post id发出请求并将结果推送到数组。像这样:

getArticles = () => {
        axios.get(`${api}/topstories.json`)
             .then(items => {
                let articles = items.data;
                let init = articles.slice(0,50);
                init.forEach(item => {
                    axios.get(`${post}/${item}.json`)
                         .then(article => {
                             this.setState({ articles: [...this.state.articles, article.data]});
                    });
            })
        });
}

然后,我有第二个函数,它接收这些信息并将其输出到帖子列表。像这样:

mapArticles = () => {
        let articles = this.state.articles.map((item, i) => {
            let time = moment.unix(item.time).fromNow();
            return(
                <section className="article" key={i}>
                    <Link className="article--link" to={`/posts/${item.id}`}/>
                    <div className="article--score">
                        <FontAwesomeIcon icon="angle-up"/>
                        <p>{item.score}</p>
                        <FontAwesomeIcon icon="angle-down"/>
                    </div>
                    <div className="article--content">
                        <div className="article--title">
                            <h1>{item.title}</h1>
                        </div>
                        <div className="article--meta">
                            {item.by} posted {time}. {item.descendants ? `${item.descendants} comments.` : null} 
                        </div>
                    </div>
                    <div className="article--external">
                        <a href={item.link} target="_blank">
                            <FontAwesomeIcon icon="external-link-alt"/>
                        </a>

                    </div>
                </section>
            )
        });
        return articles;
    }

然后我{this.mapArticles()}在render函数中使用它来返回适当的信息。

但是,每当应用加载新的数据时,它会重新呈现整个列表,从而导致大量的混乱。即,当第一个请求完成时,它呈现第一个div。当第二个请求完成时,它会重新渲染第一个div并渲染第二个div。当第三个请求完成时,它将重新呈现第一个和第二个请求,并呈现第三个请求。

有没有办法让React认识到具有该键的div已经存在,并且当状态改变并且该函数再次运行时应该被忽略?

提问于
用户回答回答于

如果物品同时到达,请等待所有物品被取出,然后渲染:

getArticles = () => {
    axios.get(`${api}/topstories.json`)
      .then(items => {
          let articles = items.data;
          let init = articles.slice(0, 50);
          Promise.all(init.map(item => axios.get(`${post}/${item}.json`)).then(articles => {
              this.setState({
                articles
              });
            })
          });
      }

如果您真的想在获取项目后立即渲染,则可以引入一个实用程序组件,该组件在promise解析时呈现。

class RenderOnResolve extends React.Component {
    state = null
    componentDidMount() {
      this.props.promise.then(data => this.setState(data))
    }
    render() {
      return this.state && this.props.render(this.state);
    }
  }

  // usage:

  <RenderOnResolve promise={promise} render={this.articleRenderer}/>
用户回答回答于

我用来渲染新部件的技术是保留已经绘制的obj的缓存映射,因此在渲染方法中我只渲染新的传入元素。

这是一个例子:看看https://codesandbox.io/s/wq2vq09pr7

在此代码中,您可以看到List具有缓存数组,而render方法仅绘制新数组

class RealTimeList extends React.Component {
  constructor(props) {
    super(props);
    this.cache = [];
  }
  renderRow(message, key) {
    return <div key={key}>Mesage:{key}</div>;
  }
  renderMessages = () => {
    //let newMessages=this,props.newMessage
    let newElement = this.renderRow(this.props.message, this.cache.length);
    this.cache.push(newElement);
    return [...this.cache];
  };
  render() {
    return (
      <div>
        <div> Smart List</div>
        <div className="listcontainer">{this.renderMessages()}</div>
      </div>
    );
  }
}

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { message: "hi" };
  }

  start = () => {
    if (this.interval) return;
    this.interval = setInterval(this.generateMessage, 200);
  };
  stop = () => {
    clearTimeout(this.interval);
    this.interval = null;
  };

  generateMessage = () => {
    var d = new Date();
    var n = d.getMilliseconds();
    this.setState({ title: n });
  };

  render() {
    return (
      <div className="App">
        <h1>Hello CodeSandbox</h1>
        <h2>Start editing to see some magic happen!</h2>
        <button onClick={this.start}> Start</button>
        <button onClick={this.stop}> Stop</button>
        <RealTimeList message={this.state.message} />
      </div>
    );
  }
}

扫码关注云+社区

领取腾讯云代金券