2

i am newly startup react native framework here, i am using useState and useEffect to fetch data from api and store in useStete. when i render or try to fetch data from api, at the first log/render is giving me undefined and the it's giving me data for the API. The first undefined is making problem for me, so i want to avoid the first render for fetching data. it's okay for me to give direct second render for the fetch data for API.

so either how can i overcome undefined here wait until give me fetch data or directly provide me second render avoid first render of undefined.

i am really appriciate your helping,

thanks in advance!

Note: i don't want to initialize State to avoid undefined.

const [data, setData] = useState();
    useEffect(() => {
        fetch("https://jsonplaceholder.typicode.com/posts/5")
            .then((response) => response.json())
            .then((data) => setData(data))
            .catch((error) => console.error(error))
    }, []);


console.log(data);

output: enter image description here

Sabbir Ahhmed
  • 69
  • 1
  • 7

4 Answers4

2

I agree with all the previous answers, but I would also add a spinner or a skeleton component, to show that something is happening. If you don't show anything at all, the user might think that nothing is happening, and the app appears jagged/unresponsive.

(In fact the first iPhone appeared more responsive than its Android counterparts just because it had a loading animation, which gave the users the sense that something was happening, even if the process took just as long as it did on Androids)

ferrouskid
  • 466
  • 2
  • 7
2

Simply display an ActivityIndicator (spinner/loader) while data is still loading on your main return screen

return(
{
  loading?<ActivityIndicator/>:<YourComponents/>
 })

your loading state will be false on your Api or fetch function where you have to set loading true while function is called or set it by default true and false it when your state received all the required data.

1

You can avoid first render, but it is not the way you should do it. Instead check if you have data. If not, return null.

You component won’t be render while there is no data.

useEffect(…)
if(!data) return null;
return (<YourComponent />)
0
  • If you set a default value in the useState: this will be the value before the API request

  • If you don't set a default value in the useState: the default value before the API request is going to be always undefined

one way around this is to do something as follow:

import React, { useEffect, useState } from "react";

export default function MyComponent() {
  const [data, setData] = useState();
  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/posts/5")
      .then((response) => response.json())
      .then((data) => setData(data))
      .catch((error) => console.error(error));
  }, []);

  if (!data) {
    return <React.Fragment></React.Fragment>;
  }
  console.log(data);

  return <MyChildComponent>{data}</MyChildComponent>;
}

Explanation:

  if (!data) {
    return <React.Fragment></React.Fragment>;
  }
  if (!data) {
    return <></>;
  }
  if (!data) {
    return null;
  }

These options are all the same and they help you avoid rendering anything in case no data is available

Ali Zgheib
  • 128
  • 2
  • 11
  • I don't think `null` is the same as a `Fragment` – ksav Oct 28 '22 at 09:08
  • [Error: Rendered more hooks than during the previous render.] what is that means? – Sabbir Ahhmed Oct 28 '22 at 09:13
  • I believe this happens when you add a condition before useEffect/useState hooks (or possibly other React hooks) – Ali Zgheib Oct 28 '22 at 09:33
  • @ksav null is when you want your component to return nothing (empty component). you can use <> or React.Fragment (they do the same job) which is grouping child components under 1 component.. or you can use them as well to return nothing (as explained in my answer) – Ali Zgheib Oct 28 '22 at 09:37
  • https://stackoverflow.com/a/58408887/5385381 – ksav Oct 28 '22 at 11:30
  • Alright, it's working! But for me, having another issues: i am using 2 useEffect in project....2nd one i am fetching data from getting id from 1st API. now when i use if statement after 1st useEffect and call another useEffect, it's against rules..... when i use it before render, in that case it's not working for me......so basically, where i should use it in my project to work perfectly. – Sabbir Ahhmed Oct 31 '22 at 02:13
  • @AliZgheib .....btw by this same if condition will avoid empty array as well or what to do if i want to avoid first render empty array – Sabbir Ahhmed Oct 31 '22 at 07:18
  • @SabbirAhhmed you cannot avoid the first render in the useEffect hook. That's the main purpose of the hook to run some logic / do API calls on the component mount. what you can do: 1- do the 2nd API call after 1st one in the same useEffect: 2- use 2 different useEffect hooks and check if the id exists in the 2nd hook before doing the 2nd API call – Ali Zgheib Oct 31 '22 at 12:59
  • useEffect(() => { const onLoad = async () => { try { const response = await fetch( "https://jsonplaceholder.typicode.com/posts/5" ); const post = await response.json(); const data = await doSecondAPICall(post.id); // do anything with the data response - update state etc } catch (error) { console.log(error.message); } }; onLoad(); }, []); – Ali Zgheib Oct 31 '22 at 13:00
  • const [data, setData] = useState(); useEffect(() => { fetch("https://jsonplaceholder.typicode.com/posts/5") .then((response) => response.json()) .then((data) => setData(data)) .catch((error) => console.error(error)); }, []); useEffect(() => { if (!data.id) { return; } // do 2nd API call }, []); – Ali Zgheib Oct 31 '22 at 13:03