React /component/state/useEffect

박경찬·2022년 8월 4일
0

React-component

여러개의 프로젝트를 하면서 React 개념을 제대로 알지 못하고 사용했다.

이번에 next.js 프레임 워크가 아닌 순수 react로 프로젝트 하면서 제대로 알고 넘어가고 싶어서 남긴다.!

일단 리엑트의 컴포넌트를 먼저 알고 넘어가자

컴포넌트UI 또는 기능을 부품화해서 재사용 가능하게 하는 것이다

컴포넌트는 복사/붙여넣기와는 다르다

복사/붙여넣기 코드에서 모든 UI를 노란색으로 변경하려면 코드를 하나하나 수정해야한다.

하지만, 컴포넌트는 원본 하나를 만들어서 뿌려주는 개념이다.
따라서, 원본만 변경하면 모두 적용돤다.

데이터는 각 컴포넌트에 맞게 변경하여 사용 가능하다.

React-Hooks

React-Hooks은 기존 클래스 형태만 존재했는데 클래스형은 어렵고, 복잡하여 이후에 함수형 컴포넌트 방법이 추가되었다.

하지만, 함수형 컴포넌트 그 자체만으로는 클래스형 컴포넌트의 모든 기능을 흉내낼 수 없다.

그래서 React 에서 함수형 컴포넌트에서도 클래스형 컴포넌트와 동일한 기능을 사용 가능하도록 도구를 만들어 줬다. 이 도구를 Hooks(훅) 이라고 부른다.

대표적인 Hooks 에는 useState, useEffect가 있습니다.

state 친구들 (state, setState, useState)

state란 리액트 컴포넌트에서 데이터를 담기 위한 상자다.

우리는 자바스크립트에서 데이터를 담기 위한 상자로 변수를 배웠습니다.

다시 말해, state는 컴포넌트에서 사용하는 변수다.

state: 컴포넌트에서 사용하는 변수
setState: 컴포넌트에서 사용하는 변수를 바꿔주는 기능
useState: 컴포넌트에서 사용하는 변수를 만들어주는 기능

const [변수명, 변수바꾸는기능] = 변수만드는기능(담을내용) 
const [classmate, setClassmate] = useState("철수")
setClassmate("영희")     // classmate 가 영희로 바뀝니다.

리액트에서 let을 안쓰고 state를 변수로 사용하는 이유

export default function CounterDocumentPage() {

  let count = 0; // let으로 자바스크립트 변수 만들기

  function handleClick() {
    count = count + 1; // 갯수는 증가했지만, 화면에는 반영이 안됨
    console.log(count);
  }

  return (
    <div>
      <h1>{count}</h1>
      <button onClick={handleClick}>let을 사용하여 count 증가</button>
    </div>
  );

}

let 을 사용해서 카운트 하고 그려지게 코드를 작성했지만 실제로 카운트는 가능하지만 화면에는 0에서 숫자가 올라가진 않는다.

이유는 뒷쪽의 데이터 부분만 변경 되고, 앞쪽 화면에는 반영이 되지 않았기 때문이다.

하지만, 컴포넌트 변수 state를 사용해서 화면에 그리고, setState()를 사용해서 카운트를 하면, setState() 안에서 화면을 새롭게 그리라는 명령이 실행되어 변경된 데이터가 화면에 새로 그려진다.

export default function CounterStatePage(){
    const [count, setCount]=useState(0)

    function counter(){
        setCount(count + 1)
    }

    return (
        <div>
            <div>{count}</div>
            <button onClick={counter}>카운트 올리기!!!</button>
        </div>
    )
}

리액트가 리렌더하는 방식

setstate는 비동기로 작동 한다.

setState가 동기로 작동하게되면 변경될때마다 바로 바로 렌더링을 하기 때문에 비효율 적이다.

따라서 임시 저장소에 모아두었다가 코드를 끝까지 읽고 한번에 바꿔서 렌더링한다.

생명주기 훅 useEffect

클래스형 컴포넌트에는 componentDidMout와 같은 생명주기 메서드들이 있다.

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

쉽게 말해, 특정 시점에 코드가 실행되도록 설정할 수 있다는 것이다.

메서드에 대해 간략히 요약한다면,

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

리액트 컴포넌트가 렌더링 될때마다 특정 작업 ( effect )을 실행할 수 있도록 하는 hook component가 mount, update, unmount됐을 때 작업을 처리할 수 있다.

그렇다면 함수형 컴포넌트에서의 생명주기관련 훅은 무엇일까?
바로 useEffect 다.

아래 내용은 함수형 컴포넌트와 클래스형 컴포넌트의 생명주기를 이해하기 위한 내용이다.

// 의존성 배열[]에 아무것도 넣지 않으면 Mount시에만 렌더

useEffect(()=>{
		console.log("마운트 됨!!")
	},[])
  const inputRef = useRef<HTMLInputElement>(null);

  const [count, setCount] = useState(99);


  // 1. DidMount
   componentDidMount() {
     console.log("마운트됨!!!");
     this.inputRef.current?.focus();
     // 포커스 깜빡깜빡
   }
   useEffect(() => {
     console.log("마운트됨!!!");
     inputRef.current?.focus();
   }, []);
 // 2. DidUpdate
  componentDidUpdate() {
    console.log("수정되고 다시그려짐!!!");
  }
  useEffect(() => {
    console.log("count 가 변경되면 다시그려짐!!!");
  }, [count]);
//3. WillUnmount
  componentWillUnmount() {
    console.log("컴포넌트 사라짐!!!");
    // 채팅방 나가기
    // api 요청!!!
   
  }
  useEffect(() => {
     console.log("마운트됨!!!");
    inputRef.current?.focus();
     //이부분이 끝나고 진행할 것들
    return () => {
      console.log("컴포넌트 사라짐!!!");
    };
  }, []);
// 의존성 배열이 없기 때문에 뭐 하나라도 바뀌면 무조건 다시 실행됩니다.
useEffect(()=>{
		console.log("수정하고 다시 그려짐!!")
	})

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

useEffect 사용시 주의 사항

프로젝트를 진행하면서 가장 편하면서도 골치 아팠던 useEffect..
지도API사용하면서 지도정보들을 글로벌state에 담아 여러곳에서 사용하기위해 useEffect에 setState를 넣어 사용했는데.. 이거 때문에 15개의 정보가 나오면 15번이 렌더링이 되는 현상이 발생했다... 하하하하

useEffecrt 내에서 setState를 사용할때는 정말 필요한 경우가 아니라면 지양하시는게 가장 좋다...

컴포넌트가 마운트된 이후에 setState를 적용하게 되면,

  1. state가 변경되고,
  2. 변경된 state로 컴포넌트가 다시그려지게(=리렌더) 된다.

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

0개의 댓글