Context
https://ko.reactjs.org/docs/context.html#when-to-use-context
- context를 이용하면 단계마다 일일이 props를 넘겨주지 않고도 컴포넌트 트리 전체에 데이터를 제공할 수 있다
언제?
- React 컴포넌트 트리 안에서 전역적(global)이라고 볼 수 있는 데이터를 공유할 수 있도록 고안된 방법
- 그러한 데이터로는 현재 로그인한 유저, 테마, 선호하는 언어 등이 있다
글로벌로 사용할 Theme
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | export const themes = {
 light: {
 foreground: '#000000',
 background: '#eeeeee',
 },
 dark: {
 foreground: '#ffffff',
 background: '#222222',
 },
 };
 
 export const ThemeContext = React.createContext(themes.dark);
 
 | 
ThemeChange Btn
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | import React, { useContext } from 'react';
 import { ThemeContext } from './ThemeContext';
 
 export default function ThemedButton(props) {
 const theme = useContext(ThemeContext);
 return (
 <button
 {...props}
 style={{ backgroundColor: theme.background, color: theme.foreground }}
 onClick={props.onClick}
 >
 ThemedButton
 </button>
 );
 }
 
 | 
Theme Component
- Themecontext.Provider 안쪽의 버튼은 state값이 themes.light 스타일을 갖는다
- Themecontext.Provider 바깥쪽 버튼은 ThemeContext의 디폴트 값이 dark를 스타일로 갖는다
 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 
 | import { ThemeContext, themes } from './ThemeContext';
 import ThemedButton from './ThemedButton';
 import React, { useState } from 'react';
 
 export default function Theme() {
 const [theme, setTheme] = useState(themes.light);
 const toggleTheme = () => {
 setTheme((prev) => (prev === themes.dark ? themes.light : themes.dark));
 };
 return (
 <div>
 <ThemeContext.Provider value={theme}>
 <ThemedButton onClick={toggleTheme} />
 <ThemeContext.Consumer>
 {(theme) => (
 <div
 style={{
 height: 300,
 width: 300,
 backgroundColor: theme.background,
 }}
 ></div>
 )}
 </ThemeContext.Consumer>
 </ThemeContext.Provider>
 <ThemedButton />
 </div>
 );
 }
 
 | 
Portals
- Portal은 부모 컴포넌트의 DOM 계층 구조 바깥에 있는 DOM 노드로 자식을 렌더링하는 최고의 방법을 제공
Portal을 사용하지 않았을 경우
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | import React from 'react';
 import ThankyouDialog from './ThankyouDialog';
 
 export default function Portal() {
 return (
 <div onClick={() => console.log('div')}>
 <ThankyouDialog />
 <div style={{ position: 'absolute' }}>
 <button>하하하</button>
 </div>
 </div>
 );
 }
 
 | 
 
 
- ThankyouDialog 컴포넌트보다 아래에 적힌 버튼은 모달창이 떠도 가려지지 않는다
Portal을 사용했을 경우
| 12
 3
 4
 5
 
 | <body>
 <div id="root"></div>
 <div id="portal"></div>
 </body>
 
 | 
- index.html에 root 아래 portal 생성| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | import React from 'react';import { createPortal } from 'react-dom';
 import ThankyouDialog from './ThankyouDialog';
 const Portals = (props) => {
 return createPortal(props.children, document.getElementById('portal'));
 };
 export default function Portal() {
 return (
 <div onClick={() => console.log('div')}>
 <Portals>
 <ThankyouDialog />
 </Portals>
 
 <div style={{ position: 'absolute' }}>
 <button>하하하</button>
 </div>
 </div>
 );
 }
 
 
 |  
 
- Portals 컴포넌트를 새로 생성 createPortal을 return 한다
- ThankyouDialog를 Portals로 감싸준다
 
PropTypes
Props의 타입을 확인하기 위한 도구
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 
 | import React from 'react';import propTypes from 'prop-types';
 
 const PropComponent = (props) => {
 return <div>{props.name}</div>;
 };
 
 PropComponent.defaultProps = {
 name: 'Jimmy',
 age: '8',
 };
 
 PropComponent.propTypes = {
 name: propTypes.string,
 age: propTypes.number.isRequired,
 };
 
 export default function PropTypesCom() {
 return (
 <div>
 <PropComponent />
 </div>
 );
 }
 
 | 
 
age의 propTypes는 number인데 ‘8’처럼 문자로 지정하면 에러가 뜬다
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 
 | import React from 'react';import propTypes from 'prop-types';
 
 const PropComponent = (props) => {
 return <div>{props.name}</div>;
 };
 
 PropComponent.defaultProps = {
 name: 'Jimmy',
 age: 8,
 };
 
 PropComponent.propTypes = {
 name: propTypes.string,
 age: function (props, propName, componentName) {
 if (!/7/.test(props[propName])) {
 return new Error(
 'Invalid prop `' +
 propName +
 '` supplied to' +
 ' `' +
 componentName +
 '`. Validation failed.'
 );
 }
 },
 };
 export default function PropTypesCom() {
 return (
 <div>
 <PropComponent />
 </div>
 );
 }
 
 | 
함수를 이용해 체크를 해줄수도 있다