How to check if map function is finished

Viewed 2771

UPDATE: The process of what must happen

  1. User drag and drops multiple pdf files
  2. Each of these pdf files are then visually rendered one by one for the user in a list
  3. As long as the list is still updating, a pop up will come up saying "please wait until everything is loaded"
  4. After all the pdfs are loaded, the user can read the pdf in an embed to quickly check if this is what he wants to upload and can add a title and description for each pdf.
  5. Every pdf has received an item; the user now clicks 'upload'

Brief description

So I have a map function that loads a lot of items with large file size. I want to load each result one by one, but I want to hide or block it using a 'isLoading' state until everything is finished loading.

Question

How do I check if a map function is finished loading everything?

UPDATE: My code

{this.state.pdfSrc!== null ? // IF USER HAS UPLOADED FILES
    this.state.pdfSrc.map(item => ( // MAP THROUGH THOSE FILES
        // AS LONG AS THE MAP FUNCTION KEEPS LOADING FILES, A POP UP MUST COME UP SAYING "please wait until everything is loaded"
        <div key={item.fileResult} className='uploadResultList'>
                {item.fileName}
                <embed src={item.fileResult} />
                <input type='text' placeholder='Add title*' required />
        </div>
    )) /
: 
    null
}

But this only gives me following error

Warning: Functions are not valid as a React child. This may happen if you return a Component instead of from render. Or maybe you meant to call this function rather than return it.

2 Answers

Instead of doing this in a single function, you can implement the map in your component's render() method:

render() {
  return(
    <div>
     {!!imgSrc ? (
        <PlaceholderComponents/>
      ) : this.state.imgSrc.map(item => (
           <div key={item.fileResult} className='uploadResultList'>
            <embed src={item.fileResult} />
           </div>
      }
    </div>
  )
}

However, you would need to 'load' the file data before the doing so, either using componentDidMount or componentWillMount (which is now being deprecated, so try to avoid using it). For example:

    componentDidMount() {
      getImageSrcData(); // Either a function
      this.setState({ imgSrc: imgFile }) // Or from setState
    }

If you want more info on setting state from componentDidMount, see this thread: Setting state on componentDidMount()

EDIT: You can use the React Suspense API to ensure the file loads before rendering...

    // You PDF Component from a separate file where the mapping is done:

    render() {
      return (
        <div>
         {this.state.imgSrc.map(item => (
           <div key={item.fileResult} className='uploadResultList'>
             <embed src={item.fileResult} />
           </div>}
        </div>
       )
     }

    const PleaseWaitComponent = React.lazy(() => import('./PleaseWaitComponent'));


    render() {
      return (
      // Displays <PleaseWaitComponent> until PDFComponent loads
       <React.Suspense fallback={<PleaseWaitComponent />}>
         <div>
           <PDFComponent />
         </div>
       </React.Suspense>
     );
    }

Update: You may need to look at creating a higher order component that can take another component and wait till all of those are loaded and then change the state. Perhaps something similar to react-loadable?

You don't need to pass a callback into the setState. .map isn't asynchronous and once the iteration has finished it will then move to the next line in the block.

The issue you're having here is that you're just calling map and returning JSX in the callback but it isn't going anywhere.

You should call the .map inside the render method. I'm not sure why you're trying to update the isLoading state. I think this should be handled elsewhere.

render() {
  cosnt { imgSrc } = this.state;
  return (
    {
      imgSrc.map(item => (
        <div key={item.fileResult} className="uploadResultList">
          <embed src={item.fileResult} />
        </div>
      ));
    }
  )
}
Related