ㅇㅇㅈ Blog

프론트엔드 수행중

0%

react-detail-2

Context

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

  • context를 이용하면 단계마다 일일이 props를 넘겨주지 않고도 컴포넌트 트리 전체에 데이터를 제공할 수 있다

언제?

  • React 컴포넌트 트리 안에서 전역적(global)이라고 볼 수 있는 데이터를 공유할 수 있도록 고안된 방법
  • 그러한 데이터로는 현재 로그인한 유저, 테마, 선호하는 언어 등이 있다

글로벌로 사용할 Theme

1
2
3
4
5
6
7
8
9
10
11
12
13
// ThemeContext.js
export const themes = {
light: {
foreground: '#000000',
background: '#eeeeee',
},
dark: {
foreground: '#ffffff',
background: '#222222',
},
};

export const ThemeContext = React.createContext(themes.dark);

ThemeChange Btn

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// ThemedButton.jsx
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를 스타일로 갖는다
1
2
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
// Theme.jsx
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을 사용하지 않았을 경우

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Portal.jsx
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을 사용했을 경우

1
2
3
4
5
<!-- index.html -->
<body>
<div id="root"></div>
<div id="portal"></div>
</body>
  • index.html에 root 아래 portal 생성
    1
    2
    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의 타입을 확인하기 위한 도구

1
2
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’처럼 문자로 지정하면 에러가 뜬다

1
2
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>
);
}

함수를 이용해 체크를 해줄수도 있다