最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React useEffect looping many times when fetching data and setState using fetch API - Stack Overflow

programmeradmin0浏览0评论

Why is this triggering fetchData multiple times? The console.log seems to loop almost infinitely? How do I get this to run just once onload and trigger only once when fetchData() is called later? What am I doing wrong here or missing?

const [data, setData] = useState(null);

  let fetchData = React.useCallback(async () => {
    const result = await fetch(`api/data/get`);
    const body = await result.json();
    setData(body);
    console.log(data)
  },[data])

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

Update (Additional Question): How to wait for data to populate before return() the below this now gives the error because it is null at first?: data.map is not a function

return (
    <select>
        {data.map((value, index) => {
            return <option key={index}>{value}</option>
        })}
    </select>
)

Why is this triggering fetchData multiple times? The console.log seems to loop almost infinitely? How do I get this to run just once onload and trigger only once when fetchData() is called later? What am I doing wrong here or missing?

const [data, setData] = useState(null);

  let fetchData = React.useCallback(async () => {
    const result = await fetch(`api/data/get`);
    const body = await result.json();
    setData(body);
    console.log(data)
  },[data])

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

Update (Additional Question): How to wait for data to populate before return() the below this now gives the error because it is null at first?: data.map is not a function

return (
    <select>
        {data.map((value, index) => {
            return <option key={index}>{value}</option>
        })}
    </select>
)
Share Improve this question edited Jun 15, 2020 at 4:20 ckingchris asked Jun 15, 2020 at 3:14 ckingchrisckingchris 6091 gold badge14 silver badges29 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 9

In the useCallback hook you pass data as a dependency and also simultaneously change the value of data inside the callback by calling setData, which means every time the value of data changes fetchData will be reinitialized.

In the useEffect hook fetchData is a dependency which means every time fetchData changes useEffect will be triggered. That is why you get an infinite loop.

Because you want to fetch data once when the ponent is mounted, I think useCallback is unnecessary here. There is no need to memoize the function fetchData unnecessarily.

Solution

const [data, setData] = useState(null);

useEffect(() => {
  const fetchData = async () => {
    try {
     const result = await fetch(`api/data/get`);
     const body = await result.json();
     setData(body);
    } catch(err) {
      // error handling code
    } 
  }

  // call the async fetchData function
  fetchData()

}, [])

If you want to log the value of data when it changes, you can use another useEffect to do that instead. For example,

useEffect(() => {
  console.log(data)
}, [data])

P.S. - Also don't let the promise get unhandled, please use a try...catch block to handle the error. I have updated the solution to include the try..catch block.

Edit - solution for the additional question There are two possible solutions,

Because you expect the value of data to be an array after the API call you can initialize the value of data as an empty array like,

const [data, setData] = useState([]);

But if for some reason you have to initialize the value of data as null. Here is how you can render the information returned from the API call.

// using short-circuit evaluation
return (
    <select>
        {data && data.length && data.map((value) => {
            return <option key={`select-option-${value}`}>{value}</option>
        })}
    </select>
)


// using a ternary
return (
   <div>
    { data && data.length
       ? (<select>
            {
              data.map(value => <option key={`select-option-${value}`}>{value}</option>)
            }
           </select>
         )
       : <div>Data is still loading...</div>
    }
   </div>
)

Do not use indexes as key, use something unique for the key.

发布评论

评论列表(0)

  1. 暂无评论