简体   繁体   中英

React UseState not being updated

I can't understand correctly how to update my useState. I'm receiving data via my Axios call so "applis" is not empty but it's the following that seems to stuck.

What I'm trying to do:

  • Receive the data from the first call containing the list of applications (Name, ID, and the number of APIs that this application has)
  • Take the ID of the applications to make a second call that will bring me the APIs for this application (thanks to the ID)
  • All this when the application is loaded (I have 19 applications and more than a hundred APIs)

I can display in my Accordions my different applications but in AccordionSummary, you can see that I can't get my API list for an application.

Either I have nothing (as in this post) or all the APIs are under an application to loop over and over again...

Here is my code:

 export default function documentationv2() { // Getteur - Setteur const [applis, setApplis] = useState([]); const [applicationSelect, setApplicationSelect] = useState([]); const [APIs, setAPIs] = useState([]); // Chargement const loadRessources = () => { axios.get('/api/documentation/application').then((response) => { setApplis(response.data); console.log('LesApplications: ' + JSON.stringify(response.data)) {applis.map((application) => ( setApplicationSelect(application.IDAPPLI) ))} ListeAPI(applicationSelect); }).catch((error) => console.log(error)); } const ListeAPI = (AppliID) => { console.log('SELECT: ' + AppliID) // console.log('ID: ' + AppliID) axios.get('/api/documentation/api?app_id=' + AppliID).then((response) => { setAPIs(response.data) console.log('LesAPIS: ' + response.data) }) {APIs.map((api, index) => ( console.log('API: ' + api.api_uri) ))} } useEffect(() => { console.log('Chargement....') loadRessources(); }, []) // useEffect(() => { // console.log('-> Application SELECT: ' + applicationSelect) // axios.get('/api/documentation/api?app_id=' + 1) //.then((response) => { // setAPIs(response.data) // console.log('-> APIs: ' + response.data) // }) // }, [applicationSelect]) return ( {/* -- BODY -- */} <Grid item className={classes.Body}> <Grid container className={classes.GridContainerBody}> {applis.map((application, index) => ( <div className={classes.DivContainerBody}> <Grid item className={classes.GridItemLeftBody}> <Accordion key={application.IDAPPLI} onChange={(event) => setApplicationSelect(application.NOMAPPLI)} className={classes.AccordionBody}> <AccordionSummary expandIcon={<IconButton className={classes.ButtonBodyShow} disableRipple={true}><ExpandMoreIcon/></IconButton>}> <Typography> {application.NOMAPPLI} - ({application.NBAPI}) </Typography> </AccordionSummary> <AccordionDetails className={classes.AccordionDetailsApplication}> {/* {ListeAPI(application.IDAPPLI)} */} {/* {APIs.map((api, index) => ( <div className={classes.DivDetailsApplication}> <Accordion key={index} className={classes.AccordionBody}> <AccordionSummary expandIcon={<IconButton className={classes.ButtonBodyShow} disableRipple={true}><ExpandMoreIcon/></IconButton>}> <div className={classes.AccordionSumAPI}> <Typography> {api.api_uri} </Typography> <Typography> {api.api_description} </Typography> <div className={classes.AccordionSumAPIDiv}> <Chip style={{backgroundColor: "#06d6a0"}} label={api.api_version} /> <Chip style={{backgroundColor: "#ffd166"}} label={api.api_response_type} /> </div> <div> <Typography> Créé par {api.api_creation_user} le {api.api_date_creation}. </Typography> <Typography> Modifié par {api.api_maj_user} le {api.api_date_maj}. </Typography> </div> </div> </AccordionSummary> <AccordionDetails> <Typography> Information </Typography> </AccordionDetails> </Accordion> </div> ))} */} </AccordionDetails> </Accordion> </Grid> <Grid item className={classes.GridItemRightbody}> <div> <Tooltip title="Mot de passe" placement="top" arrow> <IconButton className={classes.ButtonHeader} disableRipple={true} > <LockIcon/> </IconButton> </Tooltip> </div> <div> <Tooltip title="Télécharger doc " placement="top" arrow> <IconButton className={classes.ButtonHeader} disableRipple={true} > <GetAppIcon/> </IconButton> </Tooltip> </div> </Grid> </div> ))} </Grid> </Grid> </Grid> ) }

What the different console.log tells me:

LesApplications : [{"NOMAPPLI" : "NameValue", "IDAPPLI" : "IdValue", "NBAPI" : "ValueCount"}, ...]

SELECT : 

LesAPIS : 

Could someone explain my mistake? It must be something with the useEffect not re-rendering? I don't really understand everything here.

Sorry in advance if the title of my question does not seem clear

setApplis is asyncronous, you can't call applis.map after setApplis because your applis isn't updated yet. You must call applis.map in useEffect with dependency on it. Then in second useEffect you call ListeAPI(applicationSelect) with actual applicationSelect array.

Example:

 const loadRessources = () => {
        axios.get('/api/documentation/application')
        .then((response) => {
            setApplis(response.data);
            console.log('LesApplications : ' + JSON.stringify(response.data))
        })
        .catch((error) => console.log(error));
 }

  useEffect(() => {
    const arr = applis.map((application) => application.IDAPPLI);
    setApplicationSelect(arr);
  }, [applis]);

  useEffect(() => {
   applicationSelect.length && ListeAPI(applicationSelect);
  }, [applicationSelect]);

  useEffect(() => {
    loadRessources();
  }, [])

Another example:

 const ListeAPI = (AppliID) => {
    axios.get('/api/documentation/api?app_id=' + AppliID)
    .then((response) => {
        setAPIs(prev => [...prev, ...response.data])
        console.log('LesAPIS : ' + response.data)
    })
}

 const loadRessources = () => {
        axios.get('/api/documentation/application')
        .then((response) => {
            setApplis(response.data);
            console.log('LesApplications : ' + JSON.stringify(response.data))
        })
        .catch((error) => console.log(error));
 }


 useEffect(() => {
     applis.length && applis.forEach((application) => ListeAPI(application.IDAPPLI));
  }, [applis]);

  useEffect(() => {
    loadRessources();
  }, [])

Example how to do correct APIs object sctructure:

const [APIs, setAPIs] = useState({});
const ListeAPI = (AppliID) => {
    axios.get('/api/documentation/api?app_id=' + AppliID)
    .then((response) => {
        setAPIs(prev => {
            return {
                ...prev,
                [AppliID]: response.data
            }
        })
    })
}

JSX, then you can find needed api by applis id:

{applis.map((application, index) => (
    ...

    {APIs[application.IDAPPLI] && APIs[application.IDAPPLI].map((api, index) => (
        ...

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