Home > Software design >  Filtering fetched array in render React
Filtering fetched array in render React

Time:05-20

New to React here so please bear with me. I fetched a list of data from a server and that I put in the State though the componentDidMount function. In it, I push the data to my State array named solo. It works great until I try to render the array. I need to filter my array to map the data based on one property (categ) matching a property from another array, and create buttons in the right category. When I run my code, I only get one button rendered, whichever is first in my solo array, in which all my data appears. I'm sure it has someting to do with the asynchronous nature of fetch, but I don't understand what. Here's my code :

    componentDidMount(){
      // Get URLS from config
      const data = this.props.config.layerUrls
      // Init state values
      let categ = [...this.state.categ]
      let solo = [...this.state.solo]
      // Loop through categories
      for (let i = 0; i < data.length; i  ) {
        let donneesCateg = data[i]
        let listURLS = donneesCateg["urls"]
        categ.push({['categ']: donneesCateg["name"], ['type']: "categ", ['urls']: listURLS })
        this.setState({ categ : categ })
  
       // Loop through individual URL data
        for (let a = 0; a < listURLS.length; a  ) {
          fetch(listURLS[a]   "?f=pjson")
            .then(res => res.json())
            .then(data => {
     // Push to state array
              solo.push({['categ']: donneesCateg["name"], ["type"]: "solo", ["couche"]: data.name, ["url"]: listURLS[a] })
              this.setState({ solo : solo })

            })
        }
      }
    }

render() {
    {
      return (
          <p className="shadow-lg m-3 p-1 bg-white rounded">
            {this.state.categ.length!=0 ? this.state.categ.map(item => {
              return (
                <div>
                  <button id={item.categ} className="categ" value={item.urls} onClick={this.selectChangeMultiple}>{item.categ}</button>
                  {this.state.solo.length!=0 ? this.state.solo.filter(solo => solo.categ == item.categ).map(data =>
                    <button id={data.categ} className="btn" value={data.url} onClick={this.selectChangeSingle}>{data.couche}</button>
                  ) : <p id="loadingMsg">Solo data Loading...</p>}
                </div>
              )
            }) : <p id="loadingMsg">Categ data Loading...</p>}
          </p>
        </div>
      );
    }
  }

Note : I have to go through this loop system because the URLs I use to fetch the data are in a JSON in which they are stored by categories. Many thanks.

CodePudding user response:

In your code, any subsequent call to setState({solo: solo}) isn't recognized as an update by React. This happens because solo is always the same "object" (although mutated with push, but React comparison algorithm doesn't go so far as to compare the new and previous. It just compares the old and new solos with something like ===.

An obvious fix would be to call this.setState({ solo : [...solo] }) instead of this.setState({ solo : solo }), although it would still may cause too many extra rerenders. But it'd be a good start.

  • Related