0

I'm new to React.js On the First Time load Code shows an error when i comment this part {data.advice} and run it shows me html it also calls API 2 times it gives an Error on Reload. how to fix it?

import { Box, Button, Card, CardActions, CardContent, Container, Typography } from '@mui/material';
import axios from 'axios';
import React, { useEffect, useState } from 'react';

const Advice = () => {
    const [data, setData] = useState(null);
    const clicked = () => {
        callAPI();
    }
    const callAPI = () => {
        axios.get('https://api.adviceslip.com/advice')
            .then(respone => {
                setData(respone.data.slip)
                console.log(respone.data.slip);
            })
            .catch((error) => {
                console.log(error);
            })
    }
    useEffect(() => {
        callAPI();
    }, [])
    return (
        <Box>
            <Container>
                <Typography variant='h2' sx={{ textAlign: "center" }}>Advice App</Typography>
                <Card sx={{ maxWidth: 500, margin: "10px auto", display: "block", textAlign: "center" }}>
                    {/* <CardMedia
                        sx={{ height: 140 }}
                        image="/static/images/cards/contemplative-reptile.jpg"
                        title="green iguana"
                    /> */}
                    <CardContent>
                        <Typography gutterBottom variant="h5" component="div">
                            Advice of the Day
                        </Typography>
                        <Typography variant="body2" color="text.secondary">
                            {data.advice}
                        </Typography>
                    </CardContent>
                    <CardActions>
                        <Button size="small" onClick={clicked}>Share</Button>
                        <Button size="small">Learn More</Button>
                    </CardActions>
                </Card>
            </Container>
        </Box>
    );
};

export default Advice;

https://codesandbox.io/s/cool-wildflower-p7k6ee?file=/src/App.js

Any Help will be Appreciated

Shoaib Dev
  • 71
  • 6
  • 2
    Replace {data.advice} by {data && data.advice}. The reason for two api calls might be because you might running react app in strict mode. – CodeThing Mar 31 '23 at 10:11
  • it Works and dont show the error but it call the api 2 times – Shoaib Dev Mar 31 '23 at 10:16
  • 1
    Go to your index.js file and see if your app is wrapped by . If it is, then strict mode is rendering your app twice and it will do that in dev mode only. So that is fine. Nothing to worry about. reference: https://stackoverflow.com/questions/72489140/react-18-strict-mode-causing-component-to-render-twice – CodeThing Mar 31 '23 at 10:20

4 Answers4

1

As mentioned in the comments,

You are getting error because your code is trying to print advice property of data even before it is initialised. you can try below code to make sure it will print when data is present.

{data && data.advice}

The possible reason for sending two api calls might be because your app component is wrapped in <strict> tags. That means react is running in strict mode. This will call your effects twice and react will do that in dev mode only. So that is fine. Nothing to worry about. reference: React 18 strict mode causing component to render twice

CodeThing
  • 2,580
  • 2
  • 12
  • 25
0

On the first run, your data variable is null (from useState(null)) so then trying to access data.advice triggers an error since you cannot access object properties on a null value.

There are many ways of fixing this, but 2 of the most simple ones (just to get your job done now) are:

  1. const [data, setData] = useState({ advice: null }); - replace the initial value of data with an object. Then data.advice will render null on the first run, and nothing will be visible. You could also have a loading message instead of null, as in ...{ advice: 'Loading...' });.

  2. guard the displayed expression ({data.advice}) using either {data && data.advice || null or data ? data.advice : null, whichever you prefer. A loading message instead of null is again possible.

The double network call can be due to the Advice component being rendered twice (or re-rendered automatically) by its containing component on page load (thus running your useEffect hook twice). You need further debugging to catch that, and for us to help you'd need to update your question with the container component's code, so that we might catch the issue.

Teodor Sandu
  • 1,348
  • 1
  • 20
  • 31
0

The reason you get an error on the first render is beacuse you have "data" initialised with null. "data" is null, thus there is no "advice" property and the error you should get is "Cannot read property of null".

The use Effect hook is called after the render.

What does useEffect do? By using this Hook, you tell React that your component needs to do something after render. React will remember the function you passed (we’ll refer to it as our “effect”), and call it later after performing the DOM updates. In this effect, we set the document title, but we could also perform data fetching or call some other imperative API.

Source: https://legacy.reactjs.org/docs/hooks-effect.html

Side Note: These are the outdated docs but they should be correct, regarding this behaviour.

The solution @CodeThing provided should fix the error. It checks if "data" exists, if its not it immediately returns false and doesnt check "data.advice".

On the other hand you could initialize data as object with the advice property and set it to an empty string: { advice: ""}

Hope this helps :)

Simon
  • 1
  • 1
  • 3
0

Because you set null for the data and then you are trying to access it as an object. you should use a condition. e.g:

 <Typography variant="body2" color="text.secondary">
      {data?.advice}
  </Typography>
Alpfreda
  • 387
  • 1
  • 6