7

My API is getting called twice on browser page reload as checked in the console. Can you please suggest. I am using axios to call the API in React.

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

import {Container,Row,Col} from "reactstrap";
import "bootstrap/dist/css/bootstrap.min.css"
import './App.css';

import Axios from "axios";
import MyCard from "./MyCard";

function App() {

  const[details,setDetails]=useState({});

  const fetchDetails=async ()=>{
    const {data}=await Axios.get("https://randomuser.me/api/");
    console.log("RESPONSE:",data);
    const details=data.results[0];
    setDetails(details)
  }

  useEffect(()=>{
    fetchDetails();
  },[])

  return (
    <Container fluid className="p-4 bg-primary App">
      <Row>
        <Col md={4} className="offset-md-4 mt-4">
          <MyCard details={details}/>
        </Col>
      </Row>
    </Container>
  );
}

export default App;
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Srijan
  • 101
  • 2
  • 6
  • Does this answer your question? [Why is my function being called twice in React?](https://stackoverflow.com/questions/50819162/why-is-my-function-being-called-twice-in-react) – Nisharg Shah Jul 16 '22 at 09:20
  • Does this answer your question? [Why useEffect running twice and how to handle it well in React?](https://stackoverflow.com/questions/72238175/why-useeffect-running-twice-and-how-to-handle-it-well-in-react) – Youssouf Oumar Dec 16 '22 at 14:54

2 Answers2

19

Fixed 1

This only happens in dev mode. Going live will solved your problem.

Fixed 2

Removing strict mode will solved your problem.

For Example

root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

To

root.render(
    <App />
);

Maxwell D. Dorliea
  • 1,086
  • 1
  • 8
  • 20
  • 1
    Removing StrictMode is the last thing to do. For a more detailed answer, see https://stackoverflow.com/questions/72238175/why-useeffect-running-twice-and-how-to-handle-it-well-in-react – Youssouf Oumar Dec 16 '22 at 14:56
4

The cause of the issue is in the development of react 18 with strict mode, the useEffect will be mounted -> unmounted -> mounted, which call the API twice.

SOLUTION

You need to clean up requests or events when the component unmounted

For API requests

you need to use AbortController, to abort the request after the component unmounted on the return callback.

useEffect(() => {
  const abortController = new AbortController();
  const result = await axios.get("/api/path", {
    signal: abortController.signal
  });

  return () => {
    abortController.abort()
  }
}, [])

For DOM events

You should have a reference to the handler function and use removeEventListener on the return callback

useEffect(() => {
  const clickHandler = () => {
    // ...code
  }
  
  element.addEventListener('click', clickHandler)

  return () => {
    element.removeEventListener('click', clickHandler)
  }
}, [])

FOR UNCLEANABLE EFFECTS

You can use useRef

const shouldLog = useRef(true);

useEffect(() => {
  if (shouldLog.current) {
    shouldLog.current = false;
    console.log('logged');
  }
}, [])

XML
  • 19,206
  • 9
  • 64
  • 65
Mina
  • 14,386
  • 3
  • 13
  • 26