J'ai un composant dans React où dans useEffect
je fais deux appels d'API et définis deux états. Après toujours dans useEffect
, j'essaie de définir un autre état avec l'un des états mis à jour par l'API. Si je fais cela en gardant le paramètre entre crochets de useEffect
vide, cela ne définira pas l'état. Si je passe les constantes d'état entre crochets, cela va dans une boucle infinie.
async function fetchData() { const agentRes = await fetch("http://localhost:3004/agentsdata"); agentRes .json() .then(res => setAgents(res)) .catch(err => console.log(err)); const queueRes = await fetch("http://localhost:3004/queuedata"); queueRes .json() .then(res => setBaseQueues(res)) .catch(err => console.log(err)); } useEffect(() => { fetchData(); let pge; if (props.location.data !== undefined) { pge = props.location.data.page; } else {pge = 1;} setUser(props.match.params.user); setPage(pge); let lowerB = (0 +((pge - 1) * 10)); let upperB = 10 + ((pge - 1) * 10); setQueues(baseQueues.slice(lowerB, upperB)); // here the state is not getting set. }, [queues])
Comment faire pour que je puisse définir cet état aussi bien que je dois le faire dans useEffect
.
3 Réponses :
useEffect(() => { const doAsyncStuff = async () => { await fetchData(); // wait for this data to load const { data } = props.location; let pge = data !== undefined ? data.page : 1; setUser(props.match.params.user); setPage(pge); let lowerB = (0 +((pge - 1) * 10)); let upperB = 10 + ((pge - 1) * 10); setQueues(state => state.slice(lowerB, upperB)); // change here } doAsyncStuff(); }, [queues])
D'abord, je pense que vous devez attendre que les données se chargent, vous devez donc attendre wait fetchData ();
puis pendant le réglage code> setQueues vous devez faire setQueues (state => state.slice (lowerB, upperB));
Vous pouvez utiliser un chema plus simple:
useEffect(() => { fetchData(); }, [queues]) useEffect(() => { let pge; if (props.location.data !== undefined) { pge = props.location.data.page; } else {pge = 1;} setUser(props.match.params.user); setPage(pge); let lowerB = (0 +((pge - 1) * 10)); let upperB = 10 + ((pge - 1) * 10); setQueues(baseQueues.slice(lowerB, upperB)); // here baseQueues is updated. }, [baseQueues])
... mais vous n'avez probablement pas besoin de la majorité de cela
files d'attente
sont des données dérivées; Cette réponse était en partie correcte, j'ai supprimé les files d'attente du deuxième paramètre dans le premier useEffect et cela fonctionne correctement.
tout dépend du contexte d'utilisation, le composant entier - un tableau vide dans useEffects
ne le fait qu'une fois déclenché (comme componentDidMount
) - placez ici un accessoire / variable lorsque la refeching est nécessaire
Notez que cette implémentation est problématique car elle capture les fermetures obsolètes. Notez que votre effet dépend de props.match.params.user
et props.location.data.page
donc ils doivent être inclus dans le tableau de dépendances. Tout changement dans props.location.data.page
ne sera pas géré par l'effet conduisant à des données périmées dans l'état de baseQueues
.
@ chitova263 original n'était pas non plus conscient des modifications props.location.data.page
... vous pouvez renvoyer les deux données extraites de fetchData ()
d'origine ... nous sommes travailler sur des fragments, sans contexte approprié
@xadm ... nous travaillons sur des fragments, sans contexte approprié. Oui vous avez raison
J'ai essayé de corriger le code et donné des explications détaillées dans les commentaires sur la manière d'utiliser correctement le hook useEffect. Je vous recommande vivement de lire ce billet de blog de Dan Abramov, il sera clair la plupart de vos idées fausses sur votre utilisation du hook useEffect
//since you data fetching code does not depend on anything inside your component you can hoist it outside the component. async function getAgentData(){ try{ const response = await fetch('http://localhost:3004/agentsdata'); return await response.json(); } catch(error){ console.log(error) } } async function getQueueData{ try{ const response = await fetch('http://localhost:3004/queuedata'); return await response.json(); } catch(error){ console.log(error) } } function YourComponent(props){ // destructure your props const { location: { data }, match } = props; const { params: { user } } = props.match; // Split your hooks by concern keep the related code together useEffect(() => { setUser(user); // add ALL you dependencies for this effect }, [user]) // Second Effect useEffect(() => { const pge = (data == undefined)? 1 : data.page; const lowerB = (0 +((pge - 1) * 10)); const upperB = 10 + ((pge - 1) * 10); setPage(pge); async function fetchData(){ const agentRes = await getAgentData(); setAgents(agentRes); const queueRes = await getQueueData(); // Note: There need to first save it to state; then retrieve then slice then update again. When all you need is this setBaseQueues(queueRes.slice(lowerB, upperB)); } //call the function here fetchData(); //Add the ALL the dependencies of this effect i.e all props, functions, state variables inside //YourComponent that you have used in this effect //In this case this effect is only run when this.props.location.data is changes, which is the desired behaviour }, [ data ]) return <>Whatever</> }