티스토리 뷰

 

앞서 배운 javascript의 필수 개념들을 적용시켜 프로젝트를 생성하고 한단계씩 업그레이드 시켜가는 수업이 너무 재미있고 말그대로 신기했다. 배열을 이용해 리스트를 랜더링하고, 컴포넌트들을 최적화 시켜가는 과정이 짜릿했다.

작업을 할 때, 보통 작업을 다 마치고 나서 최적화 과정을 거치는 것일까?
작업시 어느정도 최적화과정은 기본으로 하고 가고 나중에 최종 최적화 과정을 거치는 것인지 좀더 빠른 작업을 위해서는 어떻게 시작해야하는지 궁금했다. 다음주 강의인 실전 일기장 프로젝트를 통해 어떤 과정으로 애플리케이션을 제작해나갈지 정말 기대되고 궁금하다.

수업들으면서 느낀 문제는...

자바스크립트 배열 관련 내장함수들이 익숙하지 않다보니, 강의를 듣는중에 배열안에 파라미터에 무슨값이 들어갔는지, 이렇게 해서 나온 return값이 무엇이였는지 생각이 나질 않는 것이었다....  

반복해서 들어야하는데, 진도가 생각보다 벅찬감이 조금 있다. 익숙해져서 내것이 되기까지엔 시간이 많이 필요할 것 같다.

 

사용자의 입력을 리액트에서 처리하기 위해 State를 이용. useState를 이용.

실습 중 기억하고 싶은 부분은 spread 연산자 사용법이다.

const [state, setState] = useState({
	author : "";
	content : "";
});


<input value = {state.author}
 onChange = { (e) => {
        setState({
            ...state,
            author : e.target.value
        });
    }}
/>
<textarea value = {state.content}
 onChange = { (e) => {
        setState({
            ...state,
            content : e.target.value
        });
    }}
/>

💡 원래있던 state 먼저 펼쳐주고나서!! 우리가 변경하고자 하는 state 의 property를 마지막으로 적어준다.

 

돔 요소 선택기능을 리액트가 제공하고 있다. 바로 useRef 라는 기능이다.

const authorInput = useRef(); // Html 돔요소 접근 기능 제공
<input
      ref={authorInput}
      name="author"
      value={state.author}
      onChange={handleChangeState}
  />

💡 이 authorInput 레퍼런스 객체를 input에 ref는 authorInput 이런식으로 전달해주면 authorInput 객체를 통해 input 태그에 접근이 가능하다.

💡 돔요소를 선택하는 useRef() 기능으로 생성한 레퍼런스 객체는 현재 가르키는 값을 current라는 property로 불러와서 사용할 수 있다.

 

React 에서 배열 사용하기 - 리스트 렌더링

배열에 아이템 저장해서 리스트로 보여주는 사례가 많다. 실제로 배열은 게시글이나 리스트, 피드를 표시하는데 많이 사용된다.

“ 랜더링? 화면에 표시한다! “

리액트에서 컴포넌트와 데이터 구조는 어떻게 이루어질까?

이렇게 계층구조, 트리형태의 컴포넌트 트리가 만들어지게 된다.

 

React 에서 배열 사용하기 - 데이터 추가하기

우리는 DiaryEditor에서 작성한 글을 DiaryList에 추가해주고 싶은데, 이 때 에디터에서 바로 리스트로 일기아이템 추가가 불가능하다.


이유는 리액트는 단방향으로만 데이터가 흐르기 때문이다.
그럼 어떠한 방식으로 데이터를 전달할 수 있을까?

방법은 위의 그림처럼,
리액트의 상태인 State 를 Editor와 List의 공통 부모로 끌어올려서 해결할 수 있다. 공통부모인 App 컴포넌트가 일기데이터를 배열형식의[] State 를 가지고 있고, 이 데이터 State 의 값을 DiaryList에 전달하면서 List를 랜더링하게 하고, 이 date State를 변화시킬 수 있는 setData 상태변화 함수를 DiaryEditor 에게 prop으로 전달해주기만 하면 된다.

 

💡 리액트로 만든 컴포넌트들은 이런식으로 트리형태 구조를 띠며 데이터는 위에서 아래로만 움직이게 되는 단방향 데이터 흐름이 되고 추가, 수정, 삭제같은 이벤트들은 이렇게 핸들링하는 setData같은 함수를 props로 전달해서 오히려 이런 이벤트들은 아래에서 위로 올라가는 구조라고 생각해볼 수 있다.

 

React 에서 배열 사용하기 - 데이터 삭제하기

targetId 를 제외한 게시글들을 새로운 리스트로 만들어서 저장한다 ⇒ filter 사용

const onDelete = (targetId) => {
    console.log(`${targetId}가 삭제되었습니다.`);
    const newDiaryList = data.filter((it) => it.id !== targetId);
    console.log(newDiaryList);
		setData(newDiaryList);
};

 

React 에서 배열 사용하기 - 데이터 수정하기

//게시글 수정
const onEdit = (targetId, newContent) => {
    setData(
        data.map((it) =>
            it.id === targetId ? { ...it, content: newContent } : it
        )
    );
};

 

여기서 우리가 알아야 할 개념이 있다. React의 Lifecycle 에 대해서이다.

리액트는 이와같은 라이프사이클을 가지고 있고, 우리는 이 생명주기를 이용하여 우리가 해야할 작업들을 할 수 있다.

React에서 useEffect를 사용하여 LifeCycle 제어가 가능하다.

useEffect 는 조금 특별한 기능을 할 수 있다.

import React, { useEffect, useState } from "react";

const Lifecycle = () => {
    const [count, setCount] = useState(0);
    const [text, setText] = useState("");

    useEffect(() => {
        console.log("Mount!");
    }, []); //맨 처음 Mount될때 콜백함수 호출

    useEffect(() => {
        console.log("Update!");
    }); //상태가 변할때마다 콜백함수 호출

    useEffect(() => {
        console.log(`count is update : ${count}`);
    }, [count]); //count값 변할때마다 콜백함수 호출

    useEffect(() => {
        console.log(`text is update : ${text}`);
    }, [text]); //text값 변할때마다 콜백함수 호출**

    return (
        <div style={{ padding: 20 }}>
            <div>
                {count}
                <button onClick={() => setCount(count + 1)}>+</button>
            </div>
            <div>
                <input value={text} onChange={(e) => setText(e.target.value)} />
            </div>
        </div>
    );
};
export default Lifecycle;

💡 Dependency Array를 잘 활용하면 우리가 감지하고 싶은 값만 감지하여 그 값이 변화하는 순간에만 콜백함수를 수행하도록 바꿀 수 있다.

 

Unmount 는 Mount를 제어하는 useEffect에 전달되는 callback함수가 함수를 하나 리턴하게 하면 된다. 리턴되는 함수는 Unmount시점에 실행되게 된다.

import { isVisible } from "@testing-library/user-event/dist/utils";
import React, { useEffect, useState } from "react";

const UnmountTest = () => {
    useEffect(() => {
        console.log("Mount!");

        return () => {
            // Unmount 시점에 실행되게 됨
            console.log("Unmount!");
        };
    }, []);

    return <div>Unmount Testing Component</div>;
};

const Lifecycle = () => {
    const [isVisible, setIsVisible] = useState(false);
    const toggle = () => setIsVisible(!isVisible);

    return (
        <div style={{ padding: 20 }}>
            <button onClick={toggle}>ON/OFF</button>
            {isVisible && <UnmountTest />}
        </div>
    );
};
export default Lifecycle;

 

우리가 만든 코드들을 최적화 하는 방법이 있다.

1. useMemo

성능최적화를 위한 첫번째 단계인 연산 결과를 재사용하는 방법 - Memoization을 이용한 연산 과정 최적화

최적화하고싶은, 메모이제이션 하고싶은 함수를 감싸주면 된다. 글을 수정했을 때 또 상태가 변해서 다시 랜더링 되는데, 사실 글을 수정하는것은 감정분석에 사용될것이 없다. 일기 개수라던가 비율이 변하지 않는다. 이럴때 메모이제이션 기법을 사용할 수 있다.

const getDiaryAnalysis = useMemo(() => {
        console.log("일기 분석 시작");

        const goodCount = data.filter((it) => it.emotion >= 3).length;
        const badCount = data.length - goodCount;
        const goodRatio = (goodCount / data.length) * 100;
        return { goodCount, badCount, goodRatio };
    }, [data.length]);

    const { goodCount, badCount, goodRatio } = getDiaryAnalysis();

 

2. React.memo

:함수형 컴포넌트에게 업데이트 조건을 걸자

다시 랜더링 될 필요가 없는 컴포넌트가 자신과 관련되는 없데이트로 인해서 자신도 업데이트 되는건 성능상 낭비이다. 자기가 받는 값이 변경될 때만 렌더링하도록 조건을 건다.


3. useCallback

: 메모이제이션된 콜백을 반환한다.


4. 최적화 완성

 

useReducer

: useState처럼 리액트의 상태관리를 돕는 리액트의 Hooks 이다. 상태변화로직들을 컴포넌트에서 분리할 수 있어서 컴포넌트를 가볍게 작성하는 것이 가능하다.

: 상태변화함수를 컴포넌트 바깥으로 분리하여 다양한 상태변화 로직을 컴포넌트 외부로 분리해서 switch case 문법처럼 쉽게 처리할 수 있게 바꿀 수 있다.

이제부터 앱컴포넌트의 일기데이터 state를 useState훅스가 아닌 useReducer훅스를 사용해 관리할 것이다.

const [data, dispatch] = useReducer(reducer, []);

useReducer에는 기본적으로 2개인자 전달 필요.

  1. 상태변화처리할 reducer함수
  2. data State의 초기값

 


Context

: 리액트 컴포넌트 트레이 전역적으로 데이터를 공급하는 Context API 

props drilling
부모에서 자식으로만 데이터를 전달하는 단방향 데이터흐름을 지키는 리액트를 사용하면서 발생하는 문제이다. 이러한 문제를 해결하기 위해 Context라는 개념이 생김.

 

useMemo를 활용하는 이유는 ?

앱컴포넌트가 재생성될 때 dispatches객체도 다시 재생성되게 된다. 그렇게 때문에 최적화 풀리지 않도록 useMemo를 활용한다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함