React native setInterval useState

Viewed 512

I'm creating interval counter and below code is working fine. But I have few questions about this code which I do not understand.

import React, { useState, useEffect } from 'react';
import {View, Text} from 'react-native'

const Interval = () => {
  const [seconds, setSeconds] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      console.log(`seconds: ${seconds}`)
      setSeconds(seconds => seconds + 1);
    }, 1000);
    return () => clearInterval(interval);
  }, []);

  return (
      <View>
        <Text>
          {seconds} seconds have elapsed since mounting.
        </Text>
      </View>
  );
};

export default IntervalExample;
  1. Why this is not working if I put setSeconds(seconds => seconds + 1); instead setSeconds(seconds + 1); more simply ?
  2. Why console.log(`seconds: ${seconds}`) is always log as 0 ?
2 Answers

use this ;

useEffect(() => {
    const interval = setInterval(() => {
      setSeconds(seconds + 1);
      console.log(seconds)
    }, 1000);

    return () => clearInterval(interval);
  }, [seconds]);

to run useEffect You need to pass variables as the second parameter (in your case, it is seconds). When this variable has changed then useEffect will be run again.

From docs:

If you pass an empty array ([]), the props and state inside the effect will always have their initial values. While passing [] as the second argument is closer to the familiar componentDidMount and componentWillUnmount mental model, there are usually better solutions to avoid re-running effects too often. Also, don’t forget that React defers running useEffect until after the browser has painted, so doing extra work is less of a problem.

that is way, You need to pass second varable to useEfect:

useEffect(() => {...}, [seconds])

and in that case You can use setSeconds(seconds + 1); instead of passing function.

Complete code:

useEffect(() => {
 const interval = setInterval(() => {
   console.log(`seconds: ${seconds}`)
   setSeconds(seconds + 1)
  }, 1000)
 return () => clearInterval(interval)
}, [seconds])
Related