State Lifecycle

이재홍·2022년 6월 6일
0

React

목록 보기
15/25
post-thumbnail

State LifeCycle

React 컴포넌트 안의 State와 생명주기에 대한 개념

class 컴포넌트의 생명주기(Life Cycle)

: 컴포넌트의 생명주기는 컴포넌트가 브라우저에 나타나고 업데이트 되고, 사라지게 될 때 호출되는 메서드.

→ 특정 시점에 코드가 실행되도록 설정할 수 있다는 것!

  1. 그리기 → render 인풋창 그리기
  2. 그리고 난 뒤 → componentDidMount포커스 깜빡 깜빡 하기
  3. 그리고 난 뒤 변경 → componentDidUpdate
  4. 그리고 난 뒤 사라짐 → componentWillUnmount

어떻게 구현할까?

일단 인풋이 그려져야 한다. → 그리고 난 뒤 깜빡깜빡 명령을 등록!

**// class 컴포넌트의 생명주기**
import {Component} from 'react'
import Router from 'react'

export default class ClassCounterPage  extends Component{
		state = {
					count : 0,
				}

**//라이프사이클 메서드**
componentDidMout(){
		console.log("마운트 됨")
		//input태그 선택해서 **포커스 깜빡**거리게 하기
	}
componentDidUpdate(){
		console.log("수정하고 다시 그림!!")
	}
**// 리랜더링 되고 실행되는 함수**
componentWillUnmount(){
		console.log("여기서 나갈래요")
		**//나가기 전에 마지막으로 할 것들
		// 채팅방나가기!
		// Api 요청
// 언제 쓸까? 채팅방에 접속했다고 가정했을때, 접속한 채팅방에서 나가기 버튼을 클릭하게 된다면
// 인원수가 6 -> 5 로 변할때 다른 사람들도 인원수가 변하는 걸 알아야 한다.
// 나간다 -> 백엔드에 요청 -> 백엔드가 채팅방에 접속한 다른 브라우저들에게 5라는 값을 다시 보내준다.**

	}

**// 카운트 올리기 함수**
onClickCouter = ()=>{
		console.log(this.state.conut)
		this.setState(((prev))=>({
		count : this.state.count(=prev.count) +1
			}))
	}

// 현재 페이지 나가기 함수 _ componentWillUnmount를 보기위한
onClickMove = () => {
		router.push('/')
	}
**// 화면 그리는 부분**
render(){
	return(
		<div> 
			// this는 class 자기자신을 뜻합니다.
				<div>현재 카운트 : {this.state.count}</div>
	
			// 직접 바인딩 하실때는 onClick={this.onClickCouter.bind(this)} 라고 적어주셔야 합니다.
				<button onClick={this.onClickCouter}>카운트 올리기</button>
				<button onClick={this.onClickMove}>나가기</button>
		</div>
		)
	}
}

함수형 컴포넌트로 변경

useEffect

componentDidMount

// 의존성 배열[]에 아무것도 넣지 않으면 Mount시에만 렌더해주고 끝나게 됩니다.(1번만 실행)
// 처음에만 실행되고 다시는 실행되지 않음!
useEffect(()=>{
		console.log("마운트 됨!!")
	},[])

componentDidUpdate와 비슷

// 의존성 배열이 없기 때문에 뭐 하나라도 바뀌면 **무조건 다시 실행**됩니다.
// **의존성 배열[] 이 없음! -> componentDidUpdate와 똑같지는 않음
// 처음에도 한번은 실행이 되기 때문.**
useEffect(()=>{
		console.log("수정하고 다시 그려짐!!")
	})

// someState가 수정될때만 리렌더 해주기
useEffect(()=>{
		console.log("수정하고 다시 그려짐!!")
	},[someState])

componentWillUnmount

useEffect(()=>{
		console.log("수정하고 다시 그려짐!!")

		//이부분이 끝나고 진행할 것들
		return(()=>{
			console.log("여기서 나갈래요!!")
		})

	})

componentDidUpdate와 비슷하지만 다른점 하나는, Mount 되자마자 실행되는 점.

componentDidMount, componentWillUnmount

두개를 하나로 합칠 수도 있다.

return 문을 아래로 추가시켜 준다면!

(마운트, 언마운트)

💡 useEffect의 실행 시점
생명주기 메서드,훅 은 기본적으로 렌더(화면그리기) 이후에 실행됩니다.
따라서 useEffect와 lifecycle 메서드는 렌더 이후에 실행됩니다.

useEffect 사용시 주의 사항🔥

💡 useEffect 안에서 setState의 사용🔥
→useEffecrt 내에서 setState를 사용할때는 정말 필요한 경우가 아니라면 지양하시는게 가장 좋습니다.
컴포넌트가 마운트된 이후에 setState를 적용하게 되면,
1. state가 변경되고,
2. 변경된 state로 컴포넌트가 다시그려지게(=리렌더) 됩니다.

즉, useEffecrt 내에서 setState를 사용하게 되면 불필요한 리렌더나 무한루프를 일으키게 되고 성능면에서 비효율적이게 됩니다.

// useEffect 의 잘못된 사용 예제 (1. 추가랜더링, 2. [count] 까지 잘못 설정했을시 -> 무한루프;)
  // useEffect 안에서 setState는 무한루프를 불러일으킬 수 있고 비효율적임.
  useEffect(() => {
    setCount(10);
  }, [count]);

주의 : 일단 랜더가 다 된 이후에 실행되는 것들임 useEffect

Function 생명주기

import { useEffect, useState } from "react";
import { useRouter } from "next/router";

export default function CounterPage() {
  const [count, setCount] = useState(99);
  const router = useRouter();

  // 생명주기 하나로 통합
  useEffect(() => {
    console.log("마운트됨!!!");
    // 포커스 깜빡깜빡
  }, []);

  useEffect(() => {
    console.log("수정되고 다시그려짐!!!");
  });
  //

  useEffect(() => {
    return () => {
      console.log("컴포넌트 사라짐!!!");
    };
    // 채팅방 나가기
    // api 요청!!!
  }, []);

  const onClickCounter = () => {
    setCount((prev) => prev + 1);
  };

  const onClickMove = () => {
    router.push("/");
  };



  return (
    <div>
      <div>현재카운트: {count}</div>
      <button onClick={onClickCounter}>카운트 올리기!!!</button>
      <button onClick={onClickMove}>나가기!!!</button>
    </div>
  );
}
  • useEffect 사용할때 setState 사용할때 주의하자
  • 수정되고 다시 그려지기도 처음에 화면이 그려질때 한번 실행된다.

State 올바르게 사용하기

setState()에 대해서 알아야할 3가지

state.comment = "hello"
이 코드는 다시 렌더링 하지 않음
대신에 setState() 를 사용한다.
setState({comment: "hello"})

State 업데이트는 비동기적일 수도 있다.

React는 성능을 위해 여러 setState() 호출을 단일 업데이트로 한꺼번에 처리할 수 있다.
props, state가 비동기적으로 업데이트 될 수 있기 때문에 다음 State를 계산할 때 해당 값에 의존 X

this.setState({
 counter: this.state.counter + this.props.increment,
});

다음 코드는 카운터 업데이트에 실패할 수 있다.
객체보다는 함수를 인자로 사용하는 다른 형태의 setState()를 사용한다.
그 함수는 이전 State를 첫 번째 인자로 받아들이고, 업데이트가 적용된 시점의 props를 두 번째 인자로 받아들인다.

this.setState((state, props) => ({
  counter: state.counter + props.increment
}));

화살표 함수를 사용했지만, 일반적인 함수에서도 정상적으로 작동

State 업데이트는 병합된다.

setState를 호출할 때 React는 제공한 객체를 현재 state로 병합
ex) state는 다양한 독립적인 변수를 포함할 수 있다.

 constructor(props) {
    super(props);
    this.state = {
      posts: [],
      comments: []
    };
  }

별도의 setState 호출로 이러한 변수를 독립적으로 업데이트 가능

  componentDidMount() {
    fetchPosts().then(response => {
      this.setState({
        posts: response.posts
      });
    });

    fetchComments().then(response => {
      this.setState({
        comments: response.comments
      });
    });
  }

병합은 얕게 이루어진다. setState({comments}) 는 state.posts에 영향을 주진 않지만 state.comments는 완전 대체 됨.

0개의 댓글