ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [상태관리, Front-end] props drilling? 상태관리 라이브러리의 등장 배경 확실히 알아보기
    Front-end/State management 2021. 12. 15. 19:28

     

    안녕하세요! 오늘은 프론트엔드에서의 상태관리가 등장한 배경과 해결방안등에 대해서 공부하며 알아본 내용을 포스팅하도록 하겠습니다.

    저도 이전에 상태관리 라이브러리를 이게 왜 필요한지도 모르고 배우기만 하고, 실제로 어떠한 프로젝트를 진행했는데 그 개념조차 제대로 모르니까 사용을 안하게 되게 되더라고요 ㅠㅜ.. 그래서!

     

    오늘은 우리가 상태관리가 왜 필요한지. 먼저 알아보고! 느끼고! 간단하게 사용해보도록 합시다 🥳

     

    #1. Props Drilling?

    여러분 혹시 프론트앤드 개발하던 도중 중첩된 컴포넌트들 때문에 진작 필요한 정보는 너무 하위 컴포넌트라 컴포넌트를 넘기고.. 넘기고.. 넘기고.. 했던 경험 있으신가요? 있으시다면 여러분은 이미 props drilling을 경험한 것입니다 😤

     

    사실 저도 이전에 이러한 경험을 props drilling인 줄 모르고 경험했던적이 있습니다. 저는 이게 짜증나서 view마다 json요청을 해버렸죠.. ㅎㅎㅎ😒 당연히 이렇게 해결해버릴려고 하면 안됩니다. 리퀘스트가 계속 발생해 우리의 리소스를 계속 갉아먹을테니까요!

    이렇게 구글 사이트 상단의 헤더를 가져와 보았습니다. 이 헤더가 Screen안에 있는 Header 컴포넌트에 있다고 생각해봅시다. 우리는 이 Header에게 어떻게 저의 이미지와 정보를 전달할 수 있을까요? 저에 대한 내용을 보여주어야 하는데 말이죠?

     

     

    " props drilling을 좀 더 자세히 이해하기 위해 코드로 확인해보도록 합시다! "

     

    우선 가장 상위의 App.tsx를 확인해봅시다.

     

    App.tsx

    import React, { useState } from "react";
    import { MainScreen } from "./MainScreen";
    
    export interface IUser {
      id: number,
      name: string,
      photoURL?: string,
    }
    
    function App() {
      const [user] = useState<IUser>({
        id: 2,
        name: "박상준",
        photoURL: "dfkslkekls.aws.wela.png",
      });
    
      return (
        <MainScreen {...user} />
      );
    }
    
    export default App;

    우선 App.tsx에서는 MainScreen이라는 다른 컴포넌트에 user를 props로써 보내고 있습니다. 첫 번째로 MainScreen이 props를 내려받게 되는거죠. 그럼 MainScreen 코드를 확인해봅시다.

     

     MainScreen.tsx

    import React from "react";
    import { IUser } from "./App";
    import { Header } from "./Header";
    
    export const MainScreen = (user:IUser): JSX.Element => {
      return (
        <div>
          <Header {...user} />
        </div>
      );
    };

    아이고.. 또 여기서 Header 컴포넌트에 유저의 정보를 보내줘야해서 한번 더 Header가 정보를 내려받아야 하는군요.. 그럼 마지막으로 Header 컴포넌트를 확인해보죠!

     

    Header.tsx

     import React from 'react'
    import {IUser} from './App'
    
    export const Header = (user:IUser) => {
        return (
            <div>This is Google Page, {user.id}, {user.photoURL}, {user.name}</div>
        )
    }

     

    비로소 우리가 원했던 유저의 정보를 이 컴포넌트에서 렌더링 하는군요! 😖 이렇게 상위 컴포넌트에서 또 하위 컴포넌트로, 또 하위, 또 하위로.. 컴포넌트가 드릴처럼 밑으로 뚫고 내려간다. 이래서 생긴 props drilling이란 단어입니다. 결과를 보면 다음과 같이 잘 출력될겁니다!

     

    이 것이 뭐 한 번 정도 props로 넘겨받는 정도라면 상관이 없겠지만.. 과연 이게 네 번, 다 섯번 중첩이 된다면 우리는? 이건 뭐 user 하나 찾자고 user를 가지고 있는 컴포넌트의 아버지 할아버지 고조할아버지까지 찾아봐야할 지경이죠.. 이러한 문제를 해결하기 위해 탄생한것들이..?! 🥳

     

    "State Management"

    바로 그 유명한 Redux, Apollo client, Context API, Recoil 등 상태관리 라이브러리들 입니다! 이 아이들의 컨셉은 같습니다. 우리가 상태관리할 '동적인 information data' 들을 어떠한 공간에 모아 그 곳에서 모든 정보를 관리하고 컴포넌트들에게 내려주는 것이죠! 이 것을 '스토어'라고 명칭할겁니다.

     

    컴포넌트들은 UI역할만 해! 이 것이 주 목적이라 볼 수 있습니다!

     

    아 많은 라이브러리 중 Context API의 예를 통해 이 것들이 어떻게 이 props drilling 문제를 해결했는지 컨셉을 살펴봅시다!

    우선 context.tsx라는 우리의 데이터 저장소를 만들어봅시다! 😊

     

    여담 ) 저도 타입스크립트로 useContext를 처음 사용해봐서 여기 저기 찾아보고 다녔답니다..ㅎㅎ 리액트 + 타입스크립트 함수들 타입에 대해 궁금하신 분들은 https://sangjuntech.tistory.com/12 이 곳에서 첨부된 사이트를 확인해봐도 좋을 것 같습니다! 😇

     

    context.tsx

    import React from "react";
    import { IUser } from "./App";
    
    export const UserContext = React.createContext<IUser | null>(null);
    
    export const UserContextProvider = ({ children }: { children: React.ReactNode }): JSX.Element => {
      return (
        <UserContext.Provider
        value={{ id: 1, name: "박상준", photoURL: "dfkslkekls.aws.wela.png" }}
      >
        {children}
      </UserContext.Provider>
      )
    };

    차근 차근 살펴봅시다! 이 아이의 역할은 가장 상위의 컴포넌트에 value가 담긴 Provider를 제공할겁니다! 아까 user가 지금 UserContext.Provider 에 들어가있네요! 이 프로바이더에 감싸져있는 컴포넌트들은 우리의 UserContext가 제공하는 value들을 모두 가질 수 있을 겁니다! 그럼 아까 가장 최상위 컴포넌트가 뭐였죠? App.tsx 에 바로 감싸러 가봅시다 ㅎㅎ

     

     App.tsx

    import React from "react";
    import { UserContextProvider } from "./context";
    import { MainScreen } from "./MainScreen";
    
    export interface IUser {
      id: number;
      name: string;
      photoURL?: string;
    }
    
    const App:React.FC = () => {
      return (
        <UserContextProvider>
          <MainScreen />
        </UserContextProvider>
      );
    }
    
    export default App;

    App.tsx의 하위 컴포넌트들에게 모두 UserContextProvider를 제공했습니다! 그렇다면 우리는 이제 useContext를 사용할 준비가 된 겁니다! 그렇다면?! 바로 유저 정보가 렌더링되는 Header.tsx로 가보면 될 것 같네요 !

     

    Header.tsx

    import React, { useContext } from 'react'
    import { UserContext } from './context'
    
    export const Header = () => {
        const context = useContext(UserContext);
        return (
            <div>This is Google Page,{context?.id},{context?.name}, {context?.photoURL} <b>context api로 받아옴!</b></div>
        )
    }

     

    자 우리는 context에 useContext를 이용해서 context.tsx 에서 만든 UserContext를 사용할겁니다. 이 것은 우리가 UserContextProvider를 이미 제공했기에 가능한 것이겠지요!

    랜더링도 아까와 같이 될 겁니다!

     

     

    자 이렇게! 아주 잘 랜더링 되는 것을 볼 수 있습니다! 이제 props drilling이 무엇인지, 상태관리 라이브러리가 왜 필요한지 감이 잡히셨나요? 물론 거대한 규모의 프로젝트가 아닌 경우, 이러한 상태관리는 오히려 더 귀찮아지는 작업이겠지만, 최상위 컴포넌트의 크기가 커지면 커질수록, 하위 컴포넌트가 늘어나면 늘어날수록 위에 설명한 이유 때문에 우리는 상태관리 라이브러리가 필요한 것입니다!

     

    모두, 상태관리 라이브러리가 어떤 느낌의 컨셉으로 세상에 등장한 것인지 감이 잡히셨기를 바라며! 마치겠습니다 ㅎㅎ

    오늘도 읽어주셔서 감사합니다 😃 나중에는 다른 상태관리 라이브러리들을 좀 살펴보고 포스팅을 해보도록 하겠습니다! 모두 건강하세요~

    'Front-end > State management' 카테고리의 다른 글

    [상태관리, Recoil] Recoil을 사용해보자!  (0) 2022.04.08

    댓글

sangjun's blog