简体   繁体   中英

why is useEffect executing after each render?

Im having problems with my effect hook. I only want it to render once. if I pass album.length or an empty array it returns an empty object. If the album is added as a dependency then the effect renders as an infinite loop. any help is appreciated.

const [album, setAlbum] = React.useState(initialState)
const {state} = React.useContext(AuthContext);


async function fetchData(){
 try{
  const res =await axios.get('http://localhost:5000/api/albums/all')
  const {data}= await res;
  setAlbum({...data,albums:res.data})
  console.log(album)
  }
  catch(err){
  console.log(err);
  }
}



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


_______________________________________________________

componentDidMount(){
  axios.get('http://localhost:5000/api/albums/all')
.then(res=>{
    let albums=res.data.map((album)=>{
      return(
        <div key={album._id}>
       //display the album
          </div>
         </div>
        </div>
       )
       })
this.setState({albums:albums});

}) }

const res =await axios.get('http://localhost:5000/api/albums/all')
const {data}= await res;
setAlbum({...data,albums:res.data})

Can you please explain this? Why await res and why spread data and add it as albums as well?

You could write your own hook. You should also declare the function fetchApi within the useEffect hook, that is why it re-renders the whole time.

Let's take your code and make a custom hook

import axios from 'axios';
import React, { useEffect, useState } from 'react';

function useAlbums() {
  const [albums, setAlbums] = useState([]);
  useEffect(() => {
    const fetchData = async () => {
      try {
        const { data } = await axios.get(
          'http://localhost:5000/api/albums/all',
        );
        setAlbums(data);
        console.log(albums);
      } catch (err) {
        console.log(err);
      }
    };
    fetchData();
  }, [albums]);

  return [albums, setAlbums];
}

const Component = () => {
  // use it in component
  const [albums] = useAlbums();

  return (
    <>
      {albums.map(({ _id }) => (
        <div key={_id}>{'add more content here'}</div>
      ))}
    </>
  );
};

Use with

const [albums, setAlbums] = useAlbums();

Hope this helps!

Effects always run after the browser finishes to paint (except useLayoutEffect ). Fetching data (which will be serialized into state ) inevitably will trigger an additional render

const [data, setData] = useState(null)

useEffect(() =>{
    fetchAPI().then(res => setData(res))
},[])//Will run after the first render and trigger another one

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM