💎 React

리액트 Context API, reducer

ji-hyun 2022. 3. 24. 20:50

Context API 

props 드릴링을 막아준다. (= import 해와서 props 내려줄 필요가 없다)

최대한 상위에서 다 관리해주는 것이 좋다.

 

 

(리덕스와 다른 점은 리덕스는 promise 를 제공하지 않는다. 그래서 리덕스 사가를 써야 한다. 또한 리덕스는 모든걸 상위에서 관리하지만 Context API 는 위에서 관리하되, 너무 불필요하게 위까지 가지 않도록 한다고 한 것 같다.)

 

 

 

이전 게시물의 정리를 참고하면

해당 context 파일에서는 provider 를 반환한다. 

 

이 provider 를 최상위 app.tsx 에 감싸주면 그 아래 컴포넌트에서는 provider 의 value 에 접근할 수 있게 된다.

 

// 해당 context 파일

interface ContextType {
	state: State;
    	handleStateTrue(): void;
}

const Context = React.createContext({} as ContextType);

type AuthProviderPropType = { children: React.ReactNode };

export function AuthProvider(props: AuthProviderPropType) {
	const { children } = props;
    
  return (
    <Context.Provider value={{ state, handleStateTrue }}>
      {children}
    </Context.Provider>
  );
}

 

 

 

 

 

// App.tsx

import { AuthProvider } from "./contexts";

function App(){
return (
    <AuthProvider>
      <div className="App">
        <Dashboard />
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <p>
            Edit <code>src/App.tsx</code> and save to reload.
          </p>
          <a
            className="App-link"
            href="https://reactjs.org"
            target="_blank"
            rel="noopener noreferrer"
          >
            Learn React
          </a>
        </header>
      </div>
    </AuthProvider>
  );
}

 

이렇게 import 해서 provider 로 감싸줌

 

 

 

 

이제 하위 컴포넌트인 Dashboard 에서는 어떻게 value 를 쓰는지 알아보겠다.

아까 context 파일에서 한 줄 추가하는데

useContext 까지 export 시켜준다.

 

export const useAuth = () => React.useContext(Context);

 

참고로 여기에선 useAuth 이라는 커스텀 훅을 만들어주었다.

 

 

 

 

// Dashboard.tsx

import { useAuth } from "../contexts";

export function Dashboard() {
  const { handleStateTrue } = useAuth();
  
  return (
    <div className="dashboard">
      <button onClick={handleStateTrue}>Click</button>
    </div>
  );
}

 

 

 

 

 

 

 

reducer

reducer state 를 받고 state 반환하는 단순한 함수 라고 생각하면 된다.

 

// reducer 파일

export interface State {
  value: boolean;
}

export type Action = { type: "SET_TRUE" } | { type: "SET_FALSE" };

export function reducer(state: State, action: Action): State {
  switch (action.type) {
    case "SET_TRUE": {
      return { ...state, value: true }
    }
    case "SET_FALSE": {
      return { ...state, value: false }
    }
  }

 

 

 

 

 

 

 

 

 

그럼 이제 context 에 reducer 를 결합해보겠다.

다시 되짚어보면 reducer 는 state 를 받고 state 를 다시 반환하는 함수일 뿐이었다.

 

// context 파일

import { State, Action, reducer } from "./reducer";  // reducer 에서 import

interface ContextType {
  state: State;
  handleStateTrue(): void;
}

const Context = React.createContext({} as ContextType);

type AuthProviderPropType = { children: React.ReactNode };

export function AuthProvider(props: AuthProviderPropType) {
  const { children } = props;
  const [state, dispatch] = React.useReducer(reducer, { value: false });

  const handleStateTrue = () => {
    dispatch({ type: "SET_TRUE" });
  };

  return (
    <Context.Provider value={{ state, handleStateTrue }}>
      {children}
    </Context.Provider>
  );
}

export const useAuth = () => React.useContext(Context);

 

useReducer 의 첫번째 인자는 reducer, 두번째 인자는 초기값 이다.

 

state 는 우리가 앞으로 컴포넌트에서 사용 할 수 있는 상태, 

dispatch 는 액션을 발생시키는 함수.

 

 

코드리뷰에서 받았는데 setState 변수를 넘겨주는거는 자식 컴포넌트에서 부모 컴포넌트를 건드리는 건 좋지 않기 때문에 핸들러로 넘겨주는 것이 좋다고 한다.

 

 

 

 

 

import { useAuth } from "../contexts";
import React from "react";

export function Dashboard() {
  const { handleStateTrue } = useAuth();
  return (
    <div className="dashboard">
      <button onClick={handleStateTrue}>Click</button>
    </div>
  );
}

 

 

 

 

 

 

 

 

 

 

 

 

'💎 React' 카테고리의 다른 글

react lazy  (0) 2022.03.31
아폴로 클라이언트  (0) 2022.03.25
React - reducer  (0) 2022.03.08
React - Context  (0) 2022.03.07
MakeStyle 이 뭘까  (0) 2022.03.05