czechdev
czechdev

Reputation: 11

SetInterval in UseEffect without Delay

I am building a movie app in React to practice.

In the homepage there is a big banner with movie poster and information about movies, content of this banner is changing every 5 seconds. I created this function for this:

 const [movie, setMovie] = useState('');     //const movie returns object of one random movie

  useEffect(() => {
    async function fetchData() {
      const request = await axios.get(requests.fetchNetflixOriginals);  
      setMovie(
        request.data.results[
          Math.floor(Math.random() * request.data.results.length)
        ]
      );
    }
    const interval = setInterval(() => {
      fetchData();
    }, 5000)
   return () => clearInterval(interval)   
  }, [movie]);

This solution has a problem: there is a 5sec delay when I run this app for the first time (caused by setInterval).

So my question is, if there is any solution to get the same behaviour, just without the delay at the start?

I tried a lot of different solutions including defining new states, but all of them causes bugs or infinite loop.

Thanks!

Upvotes: 0

Views: 968

Answers (3)

Yulin
Yulin

Reputation: 1

I fixed the issue, after adding another useEffect hook. But i am not sure if it will call some other issue.

useEffect(() => { 
  fetchData()
})

Upvotes: 0

czechdev
czechdev

Reputation: 11

Yes, I have already tried exactly this solution with invoking function firstly and then setting an interval. But the result is that banner starts to have crazy behaviour. It changes literally 10x in a single second endlessly.

I attach a whole updated component code to be sure I didn't miss something to send:

const Banner = () => {
  const [movie, setMovie] = useState({});

  useEffect(() => {
    async function fetchData() {
        const request = await axios.get(requests.fetchNetflixOriginals);
        setMovie(
            request.data.results[
            Math.floor(Math.random() * request.data.results.length)
            ]
        );
    }
    fetchData();
    const interval = setInterval(fetchData, 5000)
    return () => {
      clearInterval(interval)
    }
}, [movie]);

  function truncate(str, n) {
    return str?.length > n ? str.substr(0, n - 1) + '...' : str;
  }

  return (
    <header
      className='banner'
      style={{
        backgroundSize: 'cover',
        backgroundImage: `url(https://image.tmdb.org/t/p/original/${movie?.backdrop_path})`, 
        backgroundPosition: 'center center',
      }}
    >
      <div className='banner__contents'>
        <h1 className='banner__title'>
          {movie?.title || movie?.name || movie?.original_name}
        </h1>
        <div className='banner__buttons'>
          <button className='banner__button'>Play</button>
          <button className='banner__button'>My List</button>
        </div>
        <h1 className='banner__description'>
          {truncate(movie?.overview, 120)}
        </h1>
      </div>
      <div className='banner--fadeBottom'></div>
    </header>
  );
};

Any ideas what should caused it/how to prevent from this behaviour?

Upvotes: 0

CertainPerformance
CertainPerformance

Reputation: 371233

Just call fetchData when defining the interval?

useEffect(() => {
    async function fetchData() {
        const request = await axios.get(requests.fetchNetflixOriginals);
        setMovie(
            request.data.results[
            Math.floor(Math.random() * request.data.results.length)
            ]
        );
    }
    fetchData();
    const interval = setInterval(fetchData, 5000)
    return () => clearInterval(interval)
}, [movie]);

Upvotes: 3

Related Questions