본문 바로가기

모바일 개발/React Native-이론

컴포넌트의 생명주기와 useEffect

1. 클래스 컴포넌트의 생명주기

클래스 컴포넌트는 생명 주기를 가지고 있다. 

클래스 컴포넌트가 시작할 때 생성자가 생성되고, 

render() 함수는 컴포넌트가 돌아갈 때 생성이 된다. 

그리고 컴포넌트가 처음 시작할 때, Spring 전 처리기 처럼 componentDidMount가 시작된다. 

componentDidUpdate는 컴포넌트가 run 되는 도중에, 업데이트(사용자의 움직임, 그에 따른 피드백)가 있을 때마다 호출 된다. 

마지막으로 컴포넌트가 종료될 때 componentWillUnmount가 호출된다. 

 

클래스 컴포넌트 내부에는 componentDidMount, componentDidUpdate, componentWillUnmount라는 함수가 따로 존재하고, 이들이 자신이 호출되어야 하는 타이밍에 자동 호출이 된다. 

 

클래스 컴포넌트는 이렇게 생명주기를 가진다. 

 

2. 함수형 컴포넌트의 생명주기 

알다시피 함수형 컴포넌트는 생명주기가 없다. 따라서 생명주기를 가지기 위해서는 useEffect라는 Hook을 써야 한다.

(1) useEffect의 형태와 기능

import {useEffect} from "react";

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

useEffect의 두 번째 인자를 의존성 배열이라고 부른다. 

여기에 특정 변수가 들어간다 . 배열 속 변수가 값이 바뀔 때, 첫 번째 인자인 함수가 실행된다.

 

 (2) useEffect로 함수형 컴포넌트에서 생명주기 구현하기 

// didMount를 나타내는 useEffect
// 의존성 배열에 아무 값도 적지 않아서, 맨 처음 컴포넌트가 run 될 때 실행 되는 경우 빼고 안 나타나게 한다.
  useEffect(() => {
    console.log('didMount')
  }, []);
  
  
// did update를 나타낸 useEffect
// 의존성 배열에 확인할 update를 적고, 해당 update가 일어났을 시 해야할 조치를 첫 번째 인자에 적는다.

  useEffect(() => {
    console.log('didUpdate - count', count)
  }, [count]);

2. 코드리뷰

import React, { useEffect, useState } from "react";
import {
  View,
  Text,
  Button,
  TextInput,
  Switch,
  ActivityIndicator,
} from "react-native";

const Component = () => {
  const [count, setCount] = useState(0);
  const [isOn, setIsOn] = useState(true);
  const [input, setInput] = useState("");
  const [isRefresh, setIsRefresh] = useState(false);

  useEffect(() => {
    console.log('didMount')
  }, []);

  useEffect(() => {
    console.log('didUpdate - count', count)
  }, [count]);

  useEffect(() => {
    console.log('didUpdate - isOn', isOn)
  }, [isOn]);

  useEffect(() => {
    console.log('didUpdate - input', input)
  }, [input]);

  useEffect(() => {
    if(isRefresh){
      setTimeout( () => {
        setIsRefresh(false);
      }, 2000);
    }
  }, [isRefresh]);

  return (
    <View style={{ alignItems: "center" }}>
      <Text>You clicked {count} times</Text>
      <Button title="Click me" onPress={() => setCount(count + 1)} />

      <Text style={{ marginVertical: 5}}>
        -------------------------------------------------
      </Text>
      <Switch value={isOn} onValueChange={setIsOn} />

      <Text style={{ marginVertical: 15 }}>
        -------------------------------------------------
      </Text>

      <Text>input: {input}</Text>
      <TextInput
        value={input}
        onChangeText={setInput}
        style={{ borderBottomWidth: 1, borderColor: "grey" }}
      />

      <Text style={{ marginVertical: 15 }}>
        -------------------------------------------------
      </Text>
      <Button
        title="새로고침!"
        onPress={() => {
          setIsRefresh(true)
        }}
      />
      {isRefresh && <ActivityIndicator/>}

    </View>
  );
};

export default Component;

(1) 클릭 시 count에 대한 것, 스위치 on/off에 대한 것, input에 값 적었을 때의 대한 것의 didUpdate가 따로 있다. 

(2) {isRefresh &&  <ActivityIndicator/>}에서 &&문은 if 문과 같다. {1번 변수 && 표현문} 1번 변수가 true일 때만 표현문이 실행된다. 

(3) <ActivityIndicator/>는 그 새로고침 시 뜨는 로딩 중 표시UI 이다.  

(4) 새로 고침 버튼을 누르면 useState Hook 덕분에 isReFresh가 true가 된다. 

    - 이는 두 가지 명령에 영향을 주는데, isRefresh가 true가 되서 밑의 로딩 중 표시가 돌아갈 것이고, 

    - 계속 로딩 중이면 안되니까, useEffect를 통해 isRefresh 값이 true로 바뀔 시 2초 뒤에 false로 토글하는 함수가 실행된다.

3. 스스로 해보기 (클릭 시 카운트 세주는 didUpdate, 토글 시도 boolean 값 찍어준느 didUpdate, 로딩 중 로직, 인풋 알려주는 didUpdate 만들기)

import React, { useEffect, useState } from "react";
import {
  View,
  Text,
  Button,
  TextInput,
  Switch,
  ActivityIndicator,
} from "react-native";


const component = () => {
  const [count, setCount] = useState(0);
  const [IsOn, setIsOn] = useState(false);
  const [name, setName] = useState("");
  const [IsFresh, setIsFresh] = useState(false);

  useEffect(
    () => {console.log("count", count)}, 
    [count])
    useEffect(
      () => {console.log("IsOn", IsOn)}, 
      [IsOn])  

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

        useEffect(
          () => {
            console.log("IsFresh", IsFresh)
            if(IsFresh){
              setTimeout( ()=> {
                setIsFresh(false)}
                , 2000);
            }  
          }, 
          [IsFresh])   
  
      return (
    <View style = {{alignItems : "center"}}>
        <Text>지금까지 {count}번 클릭 하셨습니다.</Text>
        <Button title="Click ME!" onPress={() => {setCount(count + 1)}}/>
        <Text style={{marginVertical: 15}}>--------------------------------------</Text>

        <Switch value={IsOn} onValueChange={(v) => {setIsOn(v)}}/>
        <Text style={{marginVertical: 5}}>--------------------------------------</Text>

        <TextInput 
          style={{backgroundColor:"pink"}} 
          placeholder="값을 입력하세요."
          onChangeText={(v) => {
            setName(v)
          }}
        />
        

        <Button
          title="새로고침"
          onPress={()=>{setIsFresh(true)}}
        />

        {IsFresh && <ActivityIndicator/>}

    </View>
  )

}

export default component

** Hook은 return 밖에다가 선언한다.

** setTimeOut() 의 괄호 안에 첫 번째 인자는 람다식, 두번째 인자는 시간 초는 ms