简体   繁体   中英

How can I add array items to DOM one by one?

I want to add items from an array to the DOM one by one not as a batch when the Array.map finished its loop. How can I do that?

<div className="gallery-content">
    <div className="content-to-display">
          {iconsToDisplay
             .map((icon, index) => 
                <GalleryItem 
                   key={index}
                   index={index} 
                   item={icon}
                   size={iconSize}
                   isSelected={index===selectedIconIndex}
                   onClick={this.setIconIndex}/>)}
    </div>                
</div>

I think that a convenient way of doing this is to render loading spinner or placeholder first, and then perform hevy data fetching somewhere incomponentDidMount .

This way you won't have to do delays or manually call appendChild because even large number of components will be rendered quickly initially.

UPD: see this jsfiddle for example. First, gallery items are rendered with an initial loading... message which is very fast, then I've simulated heavy loading inside the componentDidMount which had updated the state with the "loaded" content, and React had successfully rerendered them.

Maybe something like this could be usefull: https://react-bootstrap.github.io/react-overlays/#portals

You can think of it as a declarative appendChild(), or jQuery's $.fn.appendTo(). The children of component will be appended to the container specified.

An alternative approach might be the following:

Instead of looping inside JSX, you can keep index and items in the state and add an item to the list just before each render. Something like this:

state = {
  index: 0,
  galleryItems: []
}

componentDidMount() {
   // manually triggers the first component update
   this.setState({ state: this.state });
}

componentDidUpdate() {
   let galleryItems = this.state.galleryItems
   let index = this.state.index

   // loops until it reaches to the end of list
   if(index < iconsToDisplay.length - 1) {
      galleryItems.push(
         <GalleryItem 
            key={index}
            index={index} 
            item={icon}
            size={iconSize}
            isSelected={index===selectedIconIndex}
            onClick={this.setIconIndex}/>)})

      this.setState({
         index: index + 1,
         galleryItems: galleryItems
      })
   }
}

And then, you can have have this list rendered in your render() cycle. Something like this:

render() {    
   return(
     <div className="content-to-display">
       { this.state.galleryItems }
     </div>
   )
}

This way you'd render them one by one.

Disclaimer: I feel like this might work, yet I have not tried the code. I also doubt if it would in any way improve performance. I'm just mentioning it as a possible approach maybe worth giving a go and see.

Tried something with timer. Please see if this helps

在此处输入图片说明

import React, { Component } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

class App extends Component {
  constructor() {
    super();
    this.icons = [100, 200, 201, 400, 401, 404, 500, 502, 503, 504];
    this.state = {
      iconsToPlot: [],
      message: "Rendering images...",
      pendingCount: this.icons.length
    };

    let timerHandle = setInterval(() => {
      let imgNo = this.icons.pop();
      if (imgNo) {
        let pendingCount = this.icons.length;
        this.setState({
          iconsToPlot: [...this.state.iconsToPlot, imgNo],
          pendingCount: pendingCount
        });
      } else {
        clearInterval(timerHandle);
        this.setState({ message: "Timer stoped as all images are rendered." });
      }
    }, 3000);
  }

  render() {
    return (
      <div>
        <p>
          {this.state.message} Remaining {this.state.pendingCount} images{" "}
        </p>
        <ul>
          {this.state.iconsToPlot.map((key, index) => (
            <li key={index}>
              <img src={`https://http.cat/${key}`} width="150" />
            </li>
          ))}
        </ul>
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Play here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM