React, Next, Redux/🚀 React with Hooks

React Hooks : useContext ( + with TS)

DarrenKwonDev 2020. 3. 24. 02:53

Context : ko.reactjs.org/docs/context.html#when-to-use-context

useContext : ko.reactjs.org/docs/hooks-reference.html#usecontext

 

기존에 사용하던 원리와 동일합니다만, 훅을 사용하게 되면서 Provider와 context 생성만 하게 되었습니다.

Consumer가 없어지고 useContext를 사용하여 더 간결하고 편리하게 Context를 사용할 수 있습니다.

 

0. 요약

// 생성
const MyContext = React.createContext(defaultValue);

// 최상위 컴포넌트를 Provider로 감싸면 됩니다.
<MyContext.Provider value={/* 어떤 값 */}>

// useContext로 context의 값을 가져와 사용합니다.
const value = useContext(MyContext);

 

 

1. Context, Provider생성

 

src 폴더에 context.js를 생성한 후 다음과 같이 입력합니다. context.js는 Redux의 store같은 역할입니다. 여기서는 UserContext 하나만 만들지만 원하는 Context를 마음대로 만들 수 있습니다.

 

또, provider의 value는 반드시 객체 형태로 전달해줘야 합니다. 

import React, { createContext } from "react";

// context 생성
export const UserContext = createContext();

// provider 생성
const UserContextProvider = ({ children }) => {
  return (
    <UserContext.Provider value={{ name: "Darren" }}>
      {children}
    </UserContext.Provider>
  );
};

export default UserContextProvider;

 

 

2. 최상위 컴포넌트 Provider로 감싸기

 

이제 최상위 컴포넌트를 Provider로 감싸줍니다. (여기서는 UserContextProvider 입니다) 이 방식을 이용하면 이제 이 컴포넌트의 아래에 존재하는 컴포넌트는 Context의 정보를 자유롭게 사용할 수 있게 됩니다. 물론 여기서는 기껏해봐야 value라는 props 하나 뿐입니다.

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import UserContextProvider from "./context";

ReactDOM.render(
  <UserContextProvider>
    <App />
  </UserContextProvider>,
  document.getElementById("root")
);

 

context를 사용할 곳에서 context를 불러오면 됩니다. useContext 훅을 활용하여 가져올 수 있습니다.

여기서는 UserContext입니다. (위 context.js를 살펴보면 알 수 있습니다)

import React, { useContext } from "react";
import { UserContext } from "./context";

function Header() {
  const context = useContext(UserContext);
  console.log(context); // provider에서 제공한 value가 들어 있음.
  return <div>hello {context.name}</div>;
}

export default Header;

 

 

3. usestate와 함께 Context 사용하기

 

다음과 같이 state를 작성하고 그것을 props로 넘김으로써 state도 사용할 수 있습니다. 이 방법은 함수도 다른 컴포넌트로 넘길 수 있어 유용하고, context에서도 대개는 이런 방식으로 사용합니다.

 

또, provider의 value는 반드시 객체 형태로 전달해줘야 한다는 것을 잊지 맙시다. 아래 예시의 경우 (user, setuser) 형태로 보내면 상태 관리를 할 수 없게 됩니다. {user, setuser} 형태로 보냅시다.

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

export const UserContext = createContext();

const UserContextProvider = ({ children }) => {

  const [user, setuser] = useState({
    name: "darren",
    loggedIn: false,
  });
  
  const logUserIn = () => setuser({ ...user, loggedIn: true });
  
  return (
    <UserContext.Provider value={{ user, logUserIn }}>
      {children}
    </UserContext.Provider>
  );
};

export default UserContextProvider;

 

❤ setState 함수를 직접 전달하려고 하면 오류를 일으키는 경우가 있습니다. 위의 코드 처럼 setState를 이용하는 함수를 만들어 우회합시다.

 

4. Typescript와 함께 Context 사용하기

위 javascript의 예시에선 context 기본값을 안 줬는데, 타이핑을 해야하니 기본 값을 주고, 타이핑을 해주도록 합시다.

// context 생성. 기본값을 줘도 되고 안 줘도 됨. 준다면 제네릭 내부에 타이핑 넣을 것.
const Context = createContext<ITodoListContext>({
  todoList: [],
  addTodoList: (todo: string): void => {},
  removeTodoList: (index: number): void => {},
});

// chilren 타이핑
interface IProps {
  children: JSX.Element | Array<JSX.Element>;
}

// Context.Provider 정의
function TodoListContextProvider({ children }: IProps) {
  Provider가 children을 감싸게 만들 것
  return <Context.Provider value={{ 원하는 값 }}>{children}</Context.Provider>;
}