Carlo
Carlo

Reputation: 45

How do I fetch only once?

I want to fetch a name and a photo from a rest API called "randomuserAPI", to add to some kind of card in my website, but it just keeps fetching again and again in a loop, and never stops at one (I just want one random number and photo but it just keeps updating those things all the time).

This is my Course element, in which the card is created with the fetched data, which is fetched inside a function somewhere else.

import React, { useState } from 'react';
import '../App.css';
import {getUser} from '../library/getUsers.js'


const Course = ({author}) => { 

    const [userInfo, changeUserInfo] = useState('User')
    const [userPhoto, changeUserPhoto] = useState('https://i.sstatic.net/l60Hf.png')

    getUser(changeUserInfo, changeUserPhoto)

    return(
        <div className="course">
            <h4>{userInfo}</h4>
            <p>{author}</p>
            <img src={userPhoto} width="200px" height="200px" alt=""></img>
        </div>
    );
}

export default Course;

And this is the function which fetches the API:

export async function getUser(changeUserInfo, changeUserPhoto){

    await fetch('https://randomuser.me/api?results=3')
    .then(res => res.json())
    .then((user) => {
        changeUserInfo(`${user.results[0].name.first} ${user.results[0].name.first}`)
        changeUserPhoto(user.results[0].picture.large)
    })
}

I don´t know if anything can be wrong here, but here's the App element:

import React from 'react';
import Course from './elements/course';
import './App.css';

function App() {
  return (
    <div className="app">
      <Course 
        author = 'Tato Gucci'
      />  
    </div>
  );
}

export default App;

Upvotes: 1

Views: 5514

Answers (3)

Behemoth
Behemoth

Reputation: 21

Your concerns as far as I understood are:
You want a single result from the API. You need the result to be constant and must not change.

Instead of using https://randomuser.me/api?results=3 use https://randomuser.me/api?results=1 You were fetching 3 results and expecting a single result.

To make the result constant you need to store the fetched result in database and check the data exist or not before fetching. You only need to fetch data if its not exist in your database.

Upvotes: 0

dungmidside
dungmidside

Reputation: 518

getUser without any restriction will cause an infinity loop (component Course render > call getUser > change userInfo and userPhoto > trigger render Course > call getUser again > ...)

You have to put your function that cause side effect (fetch API) into useEffect hook, in this context is getUser(changeUserInfo, changeUserPhoto) function.

useEffect = (() => {
   getUser(changeUserInfo, changeUserPhoto)
}, [])

The empty array is make sure getUser function just run only once time.

You should read more about useEffect hook

Upvotes: 0

Vivek Doshi
Vivek Doshi

Reputation: 58533

Issue :

render -> getUser -> setting State -> re-render -> getUser .....
const Course = ({author}) => { 

    const [userInfo, changeUserInfo] = useState('User')
    const [userPhoto, changeUserPhoto] = useState('https://i.sstatic.net/l60Hf.png')

    //------------- ISSUE -------------
    // `getUser` get called when ever component get rendered
    // and it is setting up state , so it is causing re-rendering
    // so it's kind of infinte loop 
    // render -> getUser -> setState -> re-render .....
    getUser(changeUserInfo, changeUserPhoto)'

    return(
        <div className="course">
            <h4>{userInfo}</h4>
            <p>{author}</p>
            <img src={userPhoto} width="200px" height="200px" alt=""></img>
        </div>
    );
}

Solution :

You can put getUser inside useEffect : so it will get called only when component get mounts

useEffect(() => {
    getUser(changeUserInfo, changeUserPhoto)
},[]);

Upvotes: 3

Related Questions