HOW-TO GUIDES

Context를 제공하는 컴포넌트가 함수형일 때 useContext를 사용하여 context수정하는 방법

encredible 2021. 8. 10. 06:15

useContext hook

useContext hook의 return 값은 useState와는 달리 context로 등록된 value 하나뿐입니다. 따라서 Provider에게 전달해준 value 자체를 수정할 방법은 없습니다. 그래서 리액트 공식 문서를 찾아보면 하위 컴포넌트에서 상위 컴포넌트에서 정의한 context를 수정하는 예시를 보여주고 있는데 예시의 핵심은 value안에 state와 setState를 모두 전달하는 것입니다.

Context 선언 하는 방법

export const ThemeContext = React.createContext({
  theme: themes.dark,
  toggleTheme: () => {},
});

상위 컴포넌트가 클래스형일 때 context를 제공하는 방식

class App extends React.Component {
  constructor(props) {
    super(props);

    this.toggleTheme = () => {
      this.setState(state => ({
        theme:
          state.theme === themes.dark
            ? themes.light
            : themes.dark,
      }));
    };

    // state에 업데이트 메서드도 포함되어있으므로
    // 이 또한 context Provider를 통해 전달될것입니다.
    this.state = {
      theme: themes.light,
      toggleTheme: this.toggleTheme,
    };
  }

  render() {
    // Provider에 state 전체를 넘겨줍니다.
    return (
      <ThemeContext.Provider value={this.state}>
        <Content />
      </ThemeContext.Provider>
    );
  }
}

이 예시를 보면 toggleTheme이라는 함수로 theme이라는 state를 변경하고 있습니다. 이와 같이 Provider에게 state, setState를 동시에 전달하면 됩니다.

상위 컴포넌트가 함수형일 때 context를 제공하는 방식

function App() {
    const [theme, setTheme] = useState({themes.light});
    const toggleTheme = () => {
        setTheme((theme) => {
            theme === themes.dark ? themes.light : themes.dark
        });
    };

    return (
      <ThemeContext.Provider value={{theme, toggleTheme}}>
        <Content />
      </ThemeContext.Provider>
    );
}

상위 컴포넌트가 함수형일 때는 useState hook을 사용하여 코드가 짧아지고 이해하기 편하게 되었습니다. 핵심은 기존 클래스 방식에서는 constructor를 이용하여 그 안에서 state를 선언하고 setState를 이용하였던 것에서, 상위 함수형 컴포넌트에서 useState hook의 return값을 하위 컴포넌트에 전달을 하는 것으로 바꾼 것입니다.

예시의 toggleTheme 대신에 setTheme을 직접 전달해도 되고 다른 방식으로 수정해도 됩니다. 필요한 변경 방식을 함수로 만들어 내려주기만 하면 됩니다.

useContext를 사용하여 하위 컴포넌트에서 context를 수정하는 방법

import {ThemeContext} from './theme-context';

function ThemeTogglerButton() {
  const {theme, toggleTheme} = useContext(ThemeContext)
  // ThemeTogglerButton는 context로부터
  // theme 값과 함께 toggleTheme 매서드도 받고 있습니다.
  return (
    <button
      onClick={toggleTheme}
      style={{backgroundColor: theme.background}}>
      Toggle Theme
    </button>
  );
}

이와 같은 방식으로 state를 받고 state를 수정하시면 됩니다. 참고로 바로 위의 코드는 공식 홈페이지에 있는 내용을 hook 버전으로 변경한 것입니다. 여기서 주의할 사항은 useContext 를 받을 때는 [theme, toggleTheme]이 아니라 {theme, toggleTheme} 이라는 점입니다. useState hook이 아니라 Object 형태의 context를 풀어서 받기 위해서 저렇게 해야 합니다.