상세 컨텐츠

본문 제목

프로그래머 도전기 102일차

프로그래머가 될거야!

by Choyee 2024. 1. 14. 21:45

본문

오늘은

 

오늘은 일요일입니다!! 주말에도 쉬지않고 프로그래밍 공부를...!!

재밌다가도 어렵다가도 알것같다가도 모르겠는..!!

혼자 프로그래밍에게 밀당을 당하고 있습니다~~~

 

 

 

React 공부

 

<<컴포넌트 트리에 데이터 공급>>

<Props Drilling>
* Props Drilling 문제
               <App/>

  onCreate()             diaryList + onRemove(), onEdit() => 그냥 거쳐가기만 하는 Prop들이 존재함

<DiaryEditor/>         <DiaryList/>

                        onRemove(), onEdit()

                           <DiaryItem/>
=> DiaryList component는 diaryList, onRemove(), onEdit() 세개의 props를 받지만
     onRemove()와 onEdit() props는 자신이 사용하지 않는 props이다
     => 전달만 하는 component가 중간에 많이 생기게 될 경우
          props의 이름을 바꾸기도 어려워지고, 코드 작성과 수정에 악영향을 끼칠 수 있다
          = 이러한 현상을 Props Drilling 이라고 한다
=> 단방향 데이터 흐름을 지키는 React를 사용하다보면 발생하는 문제임


* Props Drilling 문제 해결
                                    <App/>
                  
                         모든 데이터
                          
            <Provider/>                                                 <Counter/>

on create()              diaryList     onRemove() onEdit()
       l                         l                   l
<DiaryEdito/>        <DiaryList/>            l                 => Context=문맥
                                                    l
                         <DiaryItem/> --------   
=> 모든 데이터를 가지고 있는 component가 Provider 라는 공급자 역할을 하는 자식 component에게
     자신이 가지고 있는 모든 데이터를 다 준다
    -> 공급자 Provider component는 자신의 자손에 해당하는 모든 component들에게 
        직통으로 데이터를 줄 수 있다
=> Context(문맥)
     = Provider component의 자식 node, 자식 component들로 배치되어
        해당 Provider component가 공급하는 모든 데이터에 접근할 수 있는 
        이런 component들의 영역을 Context, 문맥이라고 한다

* Counter component 처럼 
  Provider component의 자손으로 배치되지 않은 component는
  Provider compenent가 공급하는 데이터에 접근할 수 없으며,
  같은 문맥, Context가 아니라고 할 수 있다


<Context 문맥>

* Context 생성

const MyContext = React.createContext(defaultValue);



* Context Provider를 통한 데이터 공급

<MyContext.Provider value={전역으로 전달하고자 하는 값}>
  { /* context 안에 위치할 자식 컴포넌트들 */ }
</MyContext.Provideer>




* export, import

import React, {
  useCallback,
  useEffect,
  useMemo,
  useReducer,
  useRef,
  createContext,
} from "react";


=> React를 import할 때 = 그냥 React로 import
     = 이름을 바꿔서 import 받을 수 있다
=> useCallback, useEffect 등과 같이 부가적 기능들은 {}중괄호 비구조화 할당을 통해 import
     = import 시 이름을 바꿀 수 없다
=> "react" 파일에서 default로 import를 받을 수 있는 것은 export default가 된 그 요소만 가능
     export const 로 그냥 export 된 요소들은 그 이름을 비구조화 할당을 통해서만 import를 받을 수 있다


* App.js

import React, {
  useCallback,
  useEffect,
  useMemo,
  useReducer,
  useRef,
  createContext,
} from "react";

// data state를 전역적으로 공급할 수 있도록 도와줄
// DiaryStateContext 생성
// 다른 component들이 Context에 접근을 해서
// 사용하고 싶은 data를 받아갈 수 있도록 export를 해주어야 한다
export const DiaryStateContext = createContext(null);
// export default는 파일 하나당 하나밖에 쓸 수 없기 때문에
// 그냥 export만 해준다

// 1. 공급자 = Context가 가지고 있는 Provider component를 사용
const App = () => {
  return (
    // 2. App component가 return하고 있는 부분의 최상위 태그를 바꿔준다
    // = 공급자 component로 wrapping
    // 3. value라는 prop으로 data, 공급을 내려주어야 한다
    // = Provider component에 내려준 값은 언제든지 가져다 쓸 수 있는 값이다
    <DiaryStateContext.Provider value={data}>
      <div className="App">
        <DiaryEditor />
        <div>전체 일기 : {data.length}</div>
        <div>기분 좋은 일기 개수 : {goodCount}</div>
        <div>기분 나쁜 일기 개수 : {badCount}</div>
        <div>기분 좋은 일기 비율 : {goodRatio}%</div>
        <DiaryList />
      </div>
    </DiaryStateContext.Provider>
  );
};



* Provider Componet에 전달하는 value에 data 뿐만 아니라 
  모든 함수 component를 전달해주면 될 것 같지만,
  Provider 도 결국 component이기 때문에 prop이 바뀌어 버리면 재생성이 된다
  => Provider component가 재생성되면 그 밑에 있는 component들도 강제로 재생성된다
       = data state가 바뀔때마다 re-render가 되어 만들어 두었던 최적화가 다 풀리게 된다
  => 이러한 경우 문맥 Context를 중첩으로 사용해주면 된다

Context를 새로 하나 더 생성해준다
파일에서 Context를 생성하는 데에는 한계가 없기 때문에 많이 생성해도 된다

export const DiaryDispatchContext = createContext(null);



-> DiaryStateContext.Provider의 자식 요소로 추가해준다

  return (
    <DiaryStateContext.Provider value={data}>
      <DiaryDispatchContext.Provider value={memoizedDispatch}>
        <div className="App">
          <DiaryEditor />
          <div>전체 일기 : {data.length}</div>
          <div>기분 좋은 일기 개수 : {goodCount}</div>
          <div>기분 나쁜 일기 개수 : {badCount}</div>
          <div>기분 좋은 일기 비율 : {goodRatio}%</div>
          <DiaryList />
        </div>
      </DiaryDispatchContext.Provider>
    </DiaryStateContext.Provider>
  );


=> <DiaryStateContext.Provider value={data}> 위에 있는 
     component Provider는 state Context Provider가 되고
=> <DiaryDispatchContext.Provider value={memoizedDispatch}> 아래에 있는 
     component Provider는 dispatch Context Provider가 된다

=> onCreate, onEdit과 onRemove는 dispatch Context Provider에게 value로 전달을 해주면 된다
     onCreate, onEdit과 onRemove는 재생성되지 않는 함수들로 이루어져 있기 때문에
     dispatch Context Provider는 re-rendering 되지 않는다

=> 전달해 주어야 할 함수들을 하나의 값으로 묶어서 prop으로 전달

  // useMemo()를 활용하여 묶는다
  const memoizedDispatch = useMemo(() => {
    return { onCreate, onRemove, onEdit };
  }, []); // 재생성 되는 일이 없도록 deps를 빈 배열로 전달한다
  => useMemo를 활용하는 이유
       const dispatches = {
         onCreate, onRemove, onEdit
       }


       = useMemo를 활용하지 않고 그냥 묶어주게 되면 
          App component가 재생성 될 때 dispatches 객체도 재생성이 되기 때문이다
       = 최적화가 풀리지 않도록 방지해준다


* DiaryEditor

import { DiaryDispatchContext } from "./App";

// onCreate prop은 더이상 받지 않는다
// const DiaryEditor = React.memo(({ onCreate }) => {
const DiaryEditor = React.memo(() => {
  // 대신 DiaryDispatchContext에서 비구조화 할당으로 가져온다
  const { onCreate } = useContext(DiaryDispatchContext);





* DiaryList

import DiaryItem from "./DiaryItem";
import { useContext } from "react";
import { DiaryStateContext } from "./App";

// diaryList = App component의 data state값
// context에서 공급을 받으면 되기 때문에
// App component의 data 값을 prop으로 받을 필요가 없어짐
// DiaryDispatchContext 에서 onEdit, onRemove를 가져오므로 prop으로 받아 올 필요X
// const DiaryList = ({ onEdit, onRemove, diaryList }) => {
const DiaryList = () => {
  // useContext라는 hook을 사용하여 diaryList를 꺼내온다
  // DiaryStateContext를 인자로 받아온다 (값을 꺼내오고 싶은 Context를 인자로 받음)
  // Chrome의 React Developer Tools의 Components tap에서
  // hooks 부분의 Context가 값을 받아오는 것을 확인할 수 있다
  const diaryList = useContext(DiaryStateContext);
  return (
    <div className="DiaryList">
      <h2>일기 리스트</h2>
      <h4>{diaryList.length}개의 일기가 있습니다.</h4>
      <div>
        {diaryList.map((it) => (
          // DiaryItem에게 전달하는 props drilling도 제거를 해준다
          // <DiaryItem key={it.id} {...it} onEdit={onEdit} onRemove={onRemove} />
          <DiaryItem key={it.id} {...it} />
        ))}
      </div>
    </div>
  );
};

DiaryList.defaultProps = {
  diaryList: [],
};

export default DiaryList;






* DiaryItem

import { memo, useContext, /*useEffect,*/ useRef, useState } from "react";
import { DiaryDispatchContext } from "./App";

// onRemove와 onEdit을 더 이상 prop으로 받지 않는다
const DiaryItem = ({
  // onRemove,
  // onEdit,
  id,
  author,
  content,
  emotion,
  created_date,
}) => {
  // useEffect(() => {
  //   console.log(`${id}번 일기아이템 렌더`);
  // });

  // DiartDispatchContext로 부터 onRemove와 onEditd을 받아온다
  const { onRemove, onEdit } = useContext(DiaryDispatchContext);



 

 

 

 

 

Question

 

React를 공부하다보니 새삼 어렵다는 것을 느끼며

궁금했던 것들을 모아 정리를 한번 해보았습니다

 

 

 

* 비구조화 할당
비구조화 할당(destructuring assignment)은 객체나 배열에서 데이터를 추출하여 
변수에 할당하는 JavaScript의 문법 중 하나입니다. 
이를 통해 객체나 배열의 속성이나 요소를 개별 변수로 분해해서 할당할 수 있습니다.
ex) 

const person = { name: 'John', age: 30, country: 'USA' };

// 기존 방식
const name = person.name;
const age = person.age;

// 비구조화 할당
const { name, age } = person;





* 중첩 Context
부모 component의 prop이 바뀌면 재생성 되면서
자식들도 모두 강제로 재생성

Context의 자식으로 Context를 만들면
부모 Context의 Provider가 재생성 될 때 자식 Context Provider는 재생성되지 않는건가..?
=> 
React Context에서는 부모 Context Provider의 value가 변경되더라도 
자식 Context Provider가 재생성되지 않습니다. 
이는 React에서 성능 최적화를 위해 특별히 처리되는 부분 중 하나입니다




* deps
deps = dependency array를 줄여서 "deps"라고 부르는 경우가 있습니다.




* dispatch 함수
React에서 dispatch 함수는 주로 컴포넌트에서 
상태를 변경하거나 액션을 처리할 때 사용됩니다.
useState 훅을 사용하여 컴포넌트의 상태를 관리합니다.




* React Hooks
React Hooks는 React 함수형 컴포넌트에서 
상태(state)와 생명주기(lifecycle) 기능을 사용할 수 있게 해주는 기능입니다. 
클래스형 컴포넌트의 기능을 함수형 컴포넌트에서도 사용할 수 있도록 도와주며, 
코드를 간결하게 만들고 재사용성을 높일 수 있게 해줍니다.

주요한 Hooks에는 useState, useEffect, useContext, useReducer 등이 있습니다. 
이들은 각각 상태를 다루는데, 생명주기와 관련된 작업을 수행하는데, 
컨텍스트를 사용하는데 도움을 주는 등 다양한 기능을 제공합니다.

Hooks는 함수형 컴포넌트에서 사용되며, 
각각의 Hook은 특정한 목적을 가지고 있어서 필요한 Hook을 선택적으로 사용할 수 있습니다. 
Hooks는 React의 함수형 프로그래밍 모델을 강화하고, 
클래스형 컴포넌트와 비교했을 때 더 간단하고 직관적인 코드를 작성할 수 있도록 돕습니다.

 

 

 

 

* feat. ChatGPT........

 

 

 

 

 

 

2023. 01. 14 (일)

관련글 더보기