Je suis actuellement en train d'apprendre moi-même le code et pour le moment plonger dans React.js. Je suis en train de créer une application simple qui affiche des informations sur la bière tirées de punkAPI ( https://punkapi.com/documentation/v2 ).
Dans mon application, je voulais ajouter une sorte de défilement "infini" qui extrairait plus de données de l'API lorsque l'utilisateur atteindrait le bas de la page.
À la moment, la méthode handleScroll fonctionne, et met à jour l'état du composant mais cela ne déclenche pas la méthode de rendu et je me demandais pourquoi.
Je me rends compte qu'il y a beaucoup de choses qui ne vont pas avec mon code et je prévoyez de le restructurer, ajoutez des booléens dans this.state pour vérifier s'il y a encore plus de données à charger, pour gérer les erreurs et pour ne pas déclencher la méthode handleScroll de manière aussi intensive.
Cependant, je me demande toujours pourquoi il n'y a pas de rendu même si l'état est mis à jour.
class BeerList extends Component { constructor() { super() this.state = { loading: false, beers: [] } this.handleScroll = this.handleScroll.bind(this) } componentDidMount() { window.addEventListener('scroll', this.handleScroll, true); this.setState({ loading: true }) fetch("https://api.punkapi.com/v2/beers?per_page=12") .then(response => response.json()) .then(data => { this.setState({ loading: false, beers: data }) }) } handleScroll() { const checkForNewBeers = () => { let lastBeerCard = document.querySelector(".beer-list > div:last-child"); let lastBeerCardOffset = lastBeerCard.offsetTop + lastBeerCard.clientHeight; let pageOffset = window.pageYOffset + window.innerHeight; if (pageOffset <= lastBeerCardOffset - 10) { return; } this.setState(prevState => { const beers = prevState.beers; const page = (prevState.beers.length / 12) + 1; fetch(`https://api.punkapi.com/v2/beers?per_page=12&page=${page}`) .then(response => response.json()) .then(data => { for (let item of data) { beers.push(item); } console.log({ beers: beers }); return { beers: beers } }); }); } document.addEventListener("scroll", function (event) { checkForNewBeers(); }); } render() { let beerCards = [] if (this.state.beers.length > 0) { beerCards = this.state.beers.map(beer => { return <BeerCard key = { beer.id } img = { beer.image_url } title = { beer.name } description = { beer.description } /> }) } return ( < div className = "container" > < div className = "row beer-list" > { beerCards } < /div> < / div > ) } } export default BeerList
Ainsi, les BeerCards sont correctement ajoutées lorsque la page se charge puis lorsque vous faites défiler la console vous montre que l'état est mis à jour (beaucoup trop mais quand même). Je m'attendrais à ce que la page charge une tonne de BeerCards mais rien ne se passe. Pourquoi cela?
3 Réponses :
Dès que vous invoquez fetch qui est la dernière instruction à l'intérieur de setState, un indéfini sera retourné. Essayez de transformer le paramètre setState en fonction asynchrone:
this.setState(async prevState => { const beers = prevState.beers; const page = prevState.beers.length / 12 + 1; let response = await fetch( `https://api.punkapi.com/v2/beers?per_page=12&page=${page}` ); response = await response.json(); for (const item of response) { beers.push(item); } console.log({ beers: beers }); return { beers: beers }; });
Merci ça marche! Mais je ne comprends pas pourquoi il renverrait un indéfini. Je dois admettre que ma connaissance du fonctionnement d'Async dans js est encore assez limitée.
puis
ne bloque pas l'exécution de la fonction appelante. Par conséquent, votre fonction retourne undefined
. await
d'autre part fait attendre JavaScript jusqu'à ce qu'une promesse se règle et renvoie son résultat. Donc, tout ce que vous écrivez après cela est assuré de ne s'exécuter qu'après la résolution de la promesse (y compris la fin de la fonction)
OK c'est très clair, merci beaucoup pour votre explication!
Au lieu de renvoyer un objet à partir de votre fetch
asynchrone, appelez setState
dans le .then()
let beers = this.state.beers; const page = (this.state.beers.length / 12) + 1; fetch(`https://api.punkapi.com/v2/beers?per_page=12&page=${page}`) .then(response => response.json()) .then(data => { for (let item of data) { beers.push(item); } this.setState({ beers }); });
Merci pour la réponse rapide! Cela semble bien plus fluide que ce que j'ai fait :)
Vous êtes si proche! En ajoutant simplement le mot-clé "async" devant "prevState" dans "this.setState" et "return await" devant "fetch", l'état de votre application doit être mis à jour et déclencher un nouveau rendu comme prévu. P >
Oui merci, quelqu'un a commenté presque les mêmes choses. Cependant, je ne comprends pas pourquoi il renverrait un undefined sans l'async. Je dois admettre que ma connaissance du fonctionnement d'Async dans js est encore assez limitée
Aucun problème! On dirait qu'Easwar l'a très bien expliqué. J'espère que cela a été utile :)
Êtes-vous sûr que l'état est mis à jour dans
handleScroll
? Dès que vous invoquez fetch qui est la dernière instruction danssetState
, un indéfini serait retourné.