react hoc , context api , recompose
- REACT & NODE
- 2021. 2. 19.
react hoc , context api , recompose
https://velopert.com/3606
https://velopert.com/3537
https://github.com/acdlite/recompose
https://reactjs.org/docs/higher-order-components.html
리액트 에서 가장 기본이 되는 부분이다. 의외로 내용이 좀 난이도가 있기 때문에 많은 개발자들이 간과하고 깊이 있게 읽어보지 않고 넘어간다. 그로 인해 계속하여 소 귀에 경 읽기가 된다. 리덕스니 사이드 이펙트니 미들웨어니 인증이니 스마트 더미 컴포넌트 니 하는 많은 내용들이 있지만 정작 실전 코드에서 고차함수, 고차컴포넌트, 컨텍스트 api 개념을 모르면 코드를 이해하지 못한다. 왜냐하면 대다수의 유명한 리덕스 를 비롯한 styled-component, theme, intl 등등 에서 이를 사용하기 때문이다.
이 부분에 사용된 것이 High Order Component 라고 할 수 있다. 즉, 고차 함수, 고차 컴포넌트이다. 한마디로 컴포넌트를 함수로 또는 컴포넌트 로 한 번 감싼 것.
const RestrictedRoute = ({ component: Component, isLoggedIn, ...rest }) => (
<Route
{...rest}
render={props =>
isLoggedIn ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/signin",
state: { from: props.location }
}}
/>
)
}
/>
);
이런식으로 더 자주 사용된 것을 볼 수 있다. 함수에서 또 다른 함수를 리턴하도록 함. (url, WrappedComponent) 형식이 아니라, (url) => (WrappedComponent) 로 한 이유는, 나중에 여러개의 HOC 를 합쳐서 사용하게 될 때 더욱 편하게 사용하기 위함이다. – compose 같은 함수를 통하여 호출을 간소화 할 수 있다고 한다.
import React, { Component } from 'react';
const withRequest = (url) => (WrappedComponent) => {
return class extends Component {
render() {
return (
<WrappedComponent {...this.props}/>
)
}
}
}
export default withRequest;
아래의 경우가 LocaleProvider, IntlProvider, ThemeProvider, DashAppHolder 등등 쭉 내려간다. 이것들이 모두 Context API 를 사용하여 만든 것이다. Context API 는 개념적으로 자체 구현되어 왔으나 16.3 버전부터 이를 편리하게 사용할 수 있는 createContext, Provider, Consumer 를 제공한다. 또한 withDirection, connect 함수들로 감싸여져 export default 되는 컴포넌트 들을 많이 보았을 텐데 이 또한 Context API , HOC 를 사용하여 만든 라이브러리 의 HOC 형식의 메소드이다.
const currentAppLocale =
AppLocale[getCurrentLanguage(config.defaultLanguage || 'english').locale];
const DashApp = () => (
<LocaleProvider locale={currentAppLocale.antd}>
<IntlProvider
locale={currentAppLocale.locale}
messages={currentAppLocale.messages}
>
<ThemeProvider theme={themes[themeConfig.theme]}>
<DashAppHolder>
<Provider store={store}>
<PublicRoutes history={history} />
</Provider>
</DashAppHolder>
</ThemeProvider>
</IntlProvider>
</LocaleProvider>
);
Boot()
.then(() => DashApp())
.catch(error => console.error(error));
Context Api 보충
redux 를 사용하면 사실 자체적으로 Context Api 이용하여 로직을 만들어 적용할 이유가 거의 없다. 앱 전역의 로딩 모달이라던가 왼쪽 메뉴 오픈 등의 기능을 만들 때 사용하면 좋지만 redux 를 사용한다면 이 또한 redux 의 상태를 이용하여 구현하면 된다. 그것이 redux 의 목적이니깐... 오히려 Context Api 로 자체적으로 추가할 경우 소스를 더럽게 만든다. 또한 redux-persist 같은 것을 적용할 때 일관성 또한 떨어뜨릴 수 있다. 하지만 redux 또한 Context Api 로 구현되어 있다. 따라서 그 원리 및 사용법을 구체적으로 알고 있음이 좋다.
1차적으로 매우 단순하게 사용할 수 있다. (https://stackoverflow.com/questions/58193424/passing-state-with-usecontext-in-typescript) 하지만 이렇게 사용하는 것은 추천하지 않는다. 그냥 단순히 Context 의 상태를 object 형태로 하고 해당 상태를 immutable 하게 set 하는 메소드로 되어 있는 구조.
2차적으로 useReducer 훅을 사용하여 리듀서 구조로 object 의 상태를 분할하여 적용하고 단순히 useContext 를 사용하는 것이 아니라 커스텀 훅을 만들어서 사용하는 방법이 있다. 1차와 같이 한개의 object 에 모든 상태가 들어 있으면 이 object 가 변경될 때 해당 object 를 useContext 로 가져와서 사용하는 이 context 에 의존하는 모든 컴포넌트들이 리렌더링 될 것이다. object 안의 한 개의 값만 변경되는데도 object 전체를 set 해야한다. {isLoading, isLeftMenuOpen, isRightMenuOpen} 과 같이 있을 때 isLoading 만 변경하고 싶어도 이 object 전체를 다시 set 해야한다. 따라서 리듀서 구조로 해주는 것이 좋다. (https://velog.io/@velopert/typescript-context-api) (https://react.vlpt.us/using-typescript/04-ts-context.html)
하지만 결국 redux 를 그냥 사용하는 것이 좋다. 전역 state 인 store 는 하나이어야 하고 가장 유명한 것이 redux 이다! redux-toolkit 으로 인해 best practice 까지 제공하지 않는가. isLoading, isLeftMenuOpen, isRightMenuOpen 과 같은 것을 구현할 때 isLoading 이 전역의 앱 전체의 로딩 모달을 보여주는 플래그라 할 경우 각각의 Thunk 액션의 loading state 들을 useSelect 하여 || 연산자로 하는 식으로 구현하는 것이 가장 좋아보인다.
그리고 React 의 portal 이라는 것의 용도와 조금 혼동될 수 있는데 portal 은 다이알로그 메시지를 띄워주기 위한 용도 같은 경우에 사용하는 것이다. context api 는 Provider 로 감싸주어서 순차적으로 자식에 자식으로 property 를 넘기는 것을 건너 뛰고 편하게 그리고 해당 component 에서만 변화에 반응하도록 하는 기술로서 전역적인 상태 관리 용도라고 한다치면 portal 은 전역적인 어떤 지점에 요소 (DOM 이라던가 React Native 라면 어떤 부분의 컴포넌트) 를 id 라던가 ref 로 기준을 잡아놓고 createPortal 을 이용해서 해당 부분에 원하는 내용을 집어넣어줄 수 있는 기술이다. 사실 ReactDOM.createPortal 이라는 메소드로서 React Native 에서는 이러한 기술이 없다. (https://m.blog.naver.com/psj9102/222141597022) html 엘리먼트야 id 같은 것으로 select 할 수 있지만 리액트 네이티브는 그런식의 요소 선택이 어렵기 때문이다.
'REACT & NODE' 카테고리의 다른 글
초짜일 때 express vs koa2 과거 의문 사항. (0) | 2021.02.24 |
---|---|
IntelliJ > preferences > editor > code style > typescript > spaces > within > ES6 import/export braces (0) | 2021.02.22 |
Cookie, Session, Auth, Token, jwt, OAuth, 인증, safari, remember_me (0) | 2021.02.19 |
ES6 정리 javascript 2015 (0) | 2021.02.08 |
redux with NGRX, store / state / reducer 개념 (0) | 2018.12.18 |