Clock2, useEffect and useState Hook

This writing is continued article from previous one. This article explains how to use setInterval function and Hooks to make mobile clock application with react native.



1. setInterval function

  • setInterval is basic function included in JavaScript. It calls call-back function at every intervals (milliseconds).
  • setInterval function returns id value, so when it is not used anymore, clearInterval should be used to prevent unnecessary memory use.
const id = setInterval(callBackFunction, interval)
callBackFunction = () => {}

clearInterval(id)

  • For the app to show the real time in every second unit, code will be as below. But below example calls setInterval function whenever App is newly rendered every second. setInterval should be called only at the first time when rendered. For this kind of issue, useEffect hook is used.
export default function App() {
  let time = new Date()
  const id = setInterval(() => {
    time = new Date()  // renew the current time
    // renewed time would be applied through below function, which renders App again
    forceUpdate()
    }, 1000)  // 1 second interval
  return <></>
}


2. useEffect hook

  • To use useEffect hook, it can be imported from react and can be used as below example.
import React, {useEffect} from 'react'

useEffect(() =>
  /* callBackFunction to be executed */
  return () => {}
  // This is executed once when component is unmounted
  // Normally here is clean-up function
  // When useEffect is executed again, clan-up function is called first and then run the useEffect
}, Dependencies)

  • If there is no value in Dependencies: the callBackFunction is executed whenever component is mounted and re-rendered.
  • [ ], empty array in Dependencies: the callBackFunction is executed only when component is rendered at first. When component re-rendering it is not executed, but after component is unmounted and mounted again, it is executed.
  • [a, b] in Dependencies:  the callBackFunction is executed whenever a or b changes.


3. useState hook

  • To use useState hook, it can be imported from react and can be used as below example.
  • Relevant component is rendered automatically again when state is changed.
import React, {useState} from 'react'

const [currentState, stateSetter] = useState(initialState);

  • With useEffect and useState hook, make App.tsx as below.
App.tsx
import React , {useEffect, useState} from 'react';
import {StyleSheet, SafeAreaView, Text} from 'react-native';

export default function App() {
  const [time, setTime] = useState(new Date())
  useEffect(() => {
    const id = setInterval(() => {   
      setTime(new Date())  // state is changed and app is newly rendered
    }, 1000)  // with 1 second interval
    return () => clearInterval(id)  // clean-up function when component is unmounted
  }, [])  // empty array: above callBackFunction is executed only at the first time when component rendered

  return (
    <SafeAreaView style={styles.safeAreaView}>
      <Text style={[styles.digitFont, styles.time]}>
        {time.toLocaleTimeString()}
      </Text>
      <Text style={styles.digitFont}>{time.toLocaleDateString()}</Text>
    </SafeAreaView>
  )
}
const styles = StyleSheet.create({
  safeAreaView: {flex: 1, alignItems: 'center', justifyContent: 'center'},
  digitFont: {fontFamily: 'MajorMonoDisplay-Regular', fontWeight: '400'},
  time: {fontSize: 50}
})
  • Why clean-up function is important?
  1. When user scroll down the app then the component would be unmounted. Or by the conditional rendering. When it is unmounted but if setInterval keeps running, memory leak happens and React would send some warning message.
  2. Later if condition is met for re-rendering and the component is rendered again, but if there is no clean-up function, then the useEffect would be duplicated.


4. Custom hook

  • Make hooks directory in src. In the hooks directory make index.ts and useClock.ts files.
$ mkdir -p src/hooks
$ cd src/hooks
$ touch index.ts useClock.ts
$ cd ../..

  • Make useClock.ts as below. This hook functions as time and will be imported in App.tsx to make it simple.
src/hooks/useClock.ts
import React, {useEffect, useState} from 'react';

export const useClock = () => {
  const [time, setTime] = useState(new Date());
  useEffect(() => {
    const id = setInterval(() => {
      setTime(new Date());
    }, 1000);
    return () => clearInterval(id);
  }, []);
  return time;
};

  • To simply import the hooks, make index.ts as below.
src/hooks/index.ts
export * from './useClock';

  • Make App.tsx as below. With custom hook App.tsx looks much simpler.
import React from 'react';
import {StyleSheet, SafeAreaView, Text} from 'react-native';
import {useClock} from './src/hooks';

export default function App() {
  const time = useClock()

  return (
    <SafeAreaView style={styles.safeAreaView}>
      <Text style={[styles.digitFont, styles.time]}>
        {time.toLocaleTimeString()}
      </Text>
      <Text style={styles.digitFont}>{time.toLocaleDateString()}</Text>
    </SafeAreaView>
  )
}
const styles = StyleSheet.create({
  safeAreaView: {flex: 1, alignItems: 'center', justifyContent: 'center'},
  digitFont: {fontFamily: 'MajorMonoDisplay-Regular', fontWeight: '400'},
  time: {fontSize: 50}
})

  • Build test with simulator would look as below. It renders again every second and showing current time.
$ npm start
$ npx react-native run-ios
$ npx react-native run-android



Comments

Mostly viewed post

Web-app dev4, Google AdMob (Banner and Interstitial ads)

About this blog