ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Context API
    Note 2021. 9. 3. 15:43

    이전까지 프로젝트를 진행하면서 전역 상태 관리를 할 때 Redux를 사용하였다. Redux를 사용할 때마다 느낀 점은 초기 세팅이 복잡하고 어려웠다는 것이다. saga, thunk 같은 다양한 미들웨어를 추가적으로 사용하여 비동기 작업이나 상태를 변경하는 과정에 추가적인 도움을 받을 수 있어 좋았지만 준비하는 과정이 꽤나 복잡했었다. 이 과정이 진행 중인 프로젝트에 비해 꽤나 무게감이 나가 다소 피곤한 부분이 있었다.

     

    그래서 전역 상태 관리가 Redux에 비해 간단하고 리액트에서 공식적으로 소개한 Context API에 대해 정리해보기로 하였다.

     

    Context API?

     

    리액트 공식문서에서는 Context를 다음과 같이 소개하고 있다.

    context를 이용하면 단계마다 일일이 props를 넘겨주지 않고도 컴포넌트 트리 전체에 데이터를 제공할 수 있습니다. 

    by 리액트

     

    Context를 생성하고 해당 상태가 필요한 컴포넌트에서 Context를 가져다 사용하면 된다. 그래서 컴포넌트 트리를 따라가며 props로 전달할 필요가 없다.

     

     

    사용방법

    로그인 여부를 전역 상태로 관리해보자.

    - 전역 상태: 로그인 여부(auth: true/false)

     

     

    React.createContext

    • createContext를 통해 상태를 저장한다.
    • defaultValue에 초기 상태 값을 객체 형태로 넣으면 된다.
    createContext(defaultValue);

    컨텍스트를 생성할 수 있는 API다. 매개변수로 defaultValue를 받는데 이 값은 컨텍스트를 사용하는 컴포넌트에서 적절한 Provider를 찾지 못했을 때 사용된다.

     

    const AuthContext = createContext({});

    이다음에 Provider를 정의할 것이므로 defaultValue는 비워뒀다.

     

     

    Context.Provider

    Provider는 컨텍스트를 구독(consumer)하는 컴포넌트에게 컨텍스트의 변화를 알려준다. 구독하는 컴포넌트는 value값을 받게 된다.

    <AuthContext.Provider value={/* 전달할 어떤 값 */}>

     

     

    Context.Consumer

    consumer는 컨텍스트의 변화를 구독하고 값을 사용한다. 이때, Consumer의 자식은 반드시 함수여야 한다. Provider 하위에 있는 컴포넌트 중에 context를 구독하는 부분이 Provider의 value가 바뀔 때마다 다시 렌더링 된다.

    <AuthContext.Consumer>
      {value => /* 값을 사용하여 React 노드 반환 */}
    </AuthContext.Consumer>

     

     

    적용

    // AuthContext.js
    
    import { createContext, useEffect, useState } from 'react';
    import { login } from './AuthService';
    
    const AuthContext = createContext({});
    
    export const AuthProvider = ({ children }) => {
      const [auth, setAuth] = useState(false);
    	
      useEffect(() => {
        setAuth(login());  // 최초 로그인 여부 확인
      }, []);
    
      return (
        <AuthContext.Provider value={{ auth, setAuth }}>
          {children}
        </AuthContext.Provider>;
      };
    
    export const AuthConsumer = AuthContext.Consumer;
    export default AuthContext;
    
    // AuthContext, AuthProvider, AuthConsumer를 나누어 export
    // Context, Provider, Consumer를 한 파일에서 관리하고 따로 사용

     

    Provider 감싸기 

    // App.js 
    
    import { AuthProvider } from './AuthContext';
    
    const App = () => {
      return (
        <AuthProvider>
          <Routes />
        </AuthProvider>
      );
        };
    
    export default App;

    로그인 여부인 auth의 변화를 감지해야 할 컴포넌트를 provider로 감싸야한다. 모든 페이지에서 로그인 여부를 알아야 하므로 최상단에 넣었다.

     

     

    Consumer로 변화 감지하기

    import { AuthConsumer } from './AuthContext';
    
    const Gnb = () => {
      return (
        <nav>		
          <Link href="/products">								
            <a>상품보기</a>					
          </Link>	
    
          <AuthConsumer>
            {({ auth, setAuth }) =>
              auth ? (		
                <>			
                 <Link href="/mypage">								
                   <a>마이페이지</a>					
                 </Link>
                 <div onClick={() => setAuth(false)}>
                  로그아웃
                 </div>
                </>
               ) : (
                <>
                 <Link href="/signup">
                  <a>회원가입</a>
                 </Link>
                 <Link href="/login">
                  <a>로그인</a>
                 </Link>
                </>
               )
             }
           </AuthConsumer>
         </nav>
      );
    };
    
    export default Gnb;

    Consumer 자식으로 provider value에 설정한 값이 전달된다.

     

     

    정리하고 보니 Redux에 비해 구조가 복잡하지 않고 추가적인 dependency 없이 가볍게 사용할 수 있어 좋은 것 같다. 하지만 전역으로 관리할 상태가 늘어난다면 Provider를 중첩해서 내려줘야 할 것 같은데 이 부분에 대해서는 다시 생각해봐야 될 것 같다.

     

    'Note' 카테고리의 다른 글

    Front-end Clean Code  (0) 2021.09.24
    webpack  (0) 2021.09.09
    Portals  (0) 2021.08.30
    옵셔널 체이닝  (0) 2021.08.24
    자바스크립트 클린 코드  (0) 2021.08.21

    댓글