[React] Inflearn 처음 만난 리엑트(React) - Context
강의
(Inflearn) 처음 만난 리엑트(React) - SOAPLE님
14강. Context
Context
- Component Tree를 통해 어떤 Component든지 쉽게 데이터에 접근할 수 있게 해준다.
- 여러 Component에서 계속해서 접근이 일어날 수 있는 데이터는 Context를 사용하는 것이 좋다.
* 하지만 Component와 Context가 접촉하면 재사용성이 떨어진다.
그래서 무조건적으로 Context를 사용하는 것은 좋지 않다.
자주 사용하는 데이터
- 로그인 여부, 로그인 정보, UI 테마, 현재 언어 등
Context를 사용하지 않고 하위 Component에 데이터를 넘겨주는 방법
- Component를 변수에 저장하여 직접 넘겨준다.
* 하지만 데이터가 많아질 수록 상위 Component에 데이터가 몰려서
상위 Compnent는 복잡해지고 하위 Component는 유연해지게 된다.
Context 생성
- React.createContext(기본값)
- Component가 렌더링될 때 상위 Component에 Provider가 없다면 입력한 기본값이 사용된다.
- 기본값으로 undefined를 넣으면 기본값이 사용되지 않는다.
import React, { createContext } from 'react';
const Context = createContext();
데이터 접근 방법
- Context.Provider
- 하위 Component들을 <Context.Provider>로 감싸주면 하위 Component들이 데이터에 접근할 수 있게 된다.
- value 속성을 사용하여 하위 Component로 데이터를 전달할 수 있다.
예시
ThemeContext Component
import React, { createContext } from 'react';
function ThemeContext = createContext();
ThemeContext.displayName = 'ThemeContext';
export default ThemeContext;
=======================================================================
MainContext Component
import React, { useContext } from 'react';
import ThemeContext from './ThemeContext';
function MainContext(props) {
const [ theme, toggleTheme ] = useContext(ThemeContext);
return (
<div
style={{
width: '100vw',
height: '100vh',
padding: '1.5rem',
backgroundColor: theme === 'light' ? 'white' : 'black',
color: theme === 'light' ? 'black' : 'white',
}}
>
<p>안녕하세요, 테마 변경 가능한 웹 사이트입니다.</p>
<button onClick={toggleTheme}>테마 변경</button>
</div>
);
}
export default MainContext;
=======================================================================
부모 Component
import { useState, useCallback } from 'react';
import ThemeContext from './ThemeContext';
import MainContext from './MainContext';
function DarkOrLight(props) {
const [ theme, setTheme ] = useState('light');
const toggleTheme = useCallback(() => {
if(theme === 'light') {
setTheme('dark');
} else if(theme === 'dark') {
setTheme('light');
}
}, [theme]);
return (
<ThemeContext.Provider value={{theme, toggleTheme}}>
<MainContext />
</ThemeContext.Provider>
);
}
export default DarkOrLight;
Consumer Component
- 데이터를 소비하는 하위 Component, 값을 지켜보다가 값이 변경될 때 재렌더링된다.
- 하나의 Provider Component는 여러 개의 Consumer Component와 연결될 수 있다. (중첩 사용이 가능하다.)
- 값이 변경됐을 때 상위 Component가 업데이트 대상이 아니더라도 하위 Component가 Context를 사용한다면 업데이트가 일어난다.
Context API 사용시 주의사항
Provider의 부모 Component가 재렌더링될 때마다 모든 하위 Consumer Component가 재렌더링된다.
따라서 value를 직접적으로 넣는 것이 아닌, State로 옮기고 해당 값을 넣어줘야한다.
* 직접 넣었을 경우, 매번 새로운 value가 생성된다.
예시
function App(props) {
const [ value, setValue ] = useState({ something: 'something' });
return (
<MyContext.Provider value={value}>
<ChildrenComponent />
</MyContext.Provider>
);
}
Class.contextType
Provider 하위에 있는 Class Component에서 Context 데이터에 접근하기 위해 사용한다. (거의 사용하지 않는다.)
MyClass.contextType = MyContext;
Context.Consumer
Context의 데이터를 구독하는 Component, Function Component에서 사용한다.
예시
<MyContext.Consumer>
{value => /*컨텍스트의 값에 따라서 컴포넌트들을 렌더링*/}
</MyContext.Consumer>
Function as a child
Context value로 함수가 오는 경우
// children이란 prop을 직접 선언하는 방식
<Profile children={name => <p>이름 : {name}</p> />
// Profile Component로 감싸서 children으로 만드는 방식
<Profile>{name => <p>이름 : {name}</p>}</Profile>
Context.displayName
Context의 Provider나 Consumer를 표시할 때 사용한다.
여러 개의 Context를 사용하는 방법
Context.Provider를 중첩해서 사용한다.
const ThemeContext = React.createContext('light');
const UserContext = React.createContext({name: 'Guest'});
...
return (
<ThemeContext.Provider value={theme}>
<UserContext.Provider value={signedInUser}>
<하위 Component>
</UserContext.Provider>
</ThemeContext.Provider>
);
* 2개 이상의 Context 값이 자주 함께 사용될 경우,
모든 값을 제공해주는 별도의 Context를 만드는 것을 고려해봐야 한다.
useContext()
- Function Component에서 더욱 쉽게 Context를 사용할 수 있는게 해주는 Hook
- Context의 값을 Component Tree 상에서 가장 가까운 상위 Provider Context에서 받아오게 된다.
- 컨텍스트 값이 변경되면 재렌더링되기 때문에 데이터가 무거울 경우 최적화를 적용해줘야 한다.
* 파라미터로 Context 객체를 넣어줘야 한다. (Consumer나 Provider를 넣어서는 안된다.)
예시
function MyComponent(props) {
const value = useContext(MyContext);
return(
...
);
}