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 solo
s 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.