티스토리 뷰
리액트 문서에서는 context를 소개하는 페이지에서 context를 쓰기 전에 component composition에 대해 고려해보라고 권장하고 있다.
context는 여러 레벨의 여러 컴포넌트에서 같은 값을 공유하도록 해주므로 props drilling을 피할 수 있고, 불필요한 리렌더링을 피할 수 있다는 장점이 있다.
다만 context에도 단점이 존재하는데,
- implicit하다.
- props를 직접 넘겨주는 방법은 코드 상에서 해당 컴포넌트의 input이 무엇인지 확인할 수 있지만 useContext로 컴포넌트 내부에서 값에 접근하게 되면 해당 컴포넌트의 사용처에서는 컴포넌트 내부에서 어떤 값이 쓰이고 있는지 보이지 않는다. 그러므로 그 컴포넌트가 context provider 내부에서 쓰일 것이라고 가정하고 쓰인 컴포넌트라면, 개발자가 실수로 context 바깥에 그 컴포넌트를 위치시켰을 때 스리슬쩍 런타임 에러가 발생할 수 있다.
- 가독성이 떨어질 수 있다. child 컴포넌트에서 context로 implicit하게 값을 사용하고, parent 컴포넌트에서는 아무 props도 받고 있지 않는 상황이라면 parent 컴포넌트를 볼 때 내부 구조에 대한 정보나 힌트를 얻기 힘들다. React는 선언적인 것이 장점인 UI 라이브러리인데, 이렇게 사용한다면 parent component가 어떻게 구성되어 있는지 알기 위해서 계속 트리를 타고 밑으로 내려가야 겨우 파악할 수 있게 된다. 그러면 코드를 여러 번 볼때마다 이 트래킹 과정이 반복되면서 시간이 들고, 내부 코드를 고칠 때도 컴포넌트 밖에서 보이지 않으므로 알아차리기 힘들다.
Component Composition
위 context의 단점들을 피할 수 있는 component composition에 대해 코드로 알아보자.
먼저 context를 사용하는 코드를 보자.
let UserContext = React.createContext();
function App() {
const [user, setUser] = setState();
return (
<>
<UserContext.Provider value={{ user }}>
{user ? <Dashboard /> : <Login onLogin={(user) => setUser(user)} />}
</UserContext.Provider>
<WelcomeMessage /> // occurs error
</>
)
}
function Dashboard() {
return (
<DashboardNav />
<DashboardContent />
)
}
function DashboardContent() {
return (
<WelcomeMessage />
)
}
function WelcomeMessage() {
let { user } = useContext(UserContext);
return (
<>
<div>Hello</div>
<div>{user.name}</div>
</>
)
}
여기서 에러가 날 수 있는 부분은 WelcomMessage를 context 바깥에서 사용했을 때이다. 예시 코드는 아주 간단한 형태이므로 문제가 되지 않겠지만 만약 트리가 크고 복잡해진다면 점점 이런 런타임 에러를 찾기 힘들어질 수 있다.
그리고 Dashboard 컴포넌트 안에 보면 여러 자식 컴포넌트로 구성되어 있지만 App 컴포넌트에서 봤을 때는 이를 알기가 어렵다. 만약 컴포넌트가 더 많아지고 복잡해진다면 트래킹하고 코드를 읽는 것이 어려워질 것이다.
이제 컴포넌트 컴포지션을 사용하는 코드를 보자.
function App() {
const [user, setUser] = setState();
return (
<>
{user
?
<Dashboard>
<DashboardNav />
<DashboardContent>
<WelcomeMessage user={user} />
</DashboardContent>
</Dashboard>
:
<Login onLogin={(user) => setUser(user)} />
}
</>
)
}
function Dashboard({children}) {
return (
<>{children}</>
)
}
function DashboardContent() {
return (
<>{children}</>
)
}
function WelcomeMessage({user}) {
return (
<>
<div>Hello</div>
<div>{user.name}</div>
</>
)
}
이 코드의 장점은
- props drilling 없이 진짜 user가 필요한 WelcomeMessage에만 user를 넘겨주고 있다.
- 선언적으로 코드의 구조와 UI를 읽을 수 있다.
그러므로 context를 사용하기 전에 component composition으로 해결될 수 있는 문제인지 고려해보고 코딩하면 부작용을 방지할 수 있을 듯하다.
Ref
https://reactjs.org/docs/context.html#before-you-use-context
https://www.youtube.com/watch?v=3XaXKiXtNjw
https://kentcdodds.com/blog/application-state-management-with-react
'공부일지(TIL) > JS Framework + Library' 카테고리의 다른 글
[React] react hook form 이란? (0) | 2021.11.07 |
---|---|
[React] useEffect에서 data fetch하기 (0) | 2021.11.07 |
[React] Reconciliation (0) | 2021.07.23 |
[Redux] Redux랑 RxJS 같이 사용하기 (feat. Redux-Observable) (0) | 2021.04.23 |
[React] re-render (0) | 2021.04.12 |
- Total
- Today
- Yesterday
- rxjs
- SQL
- CSS
- oracle
- youtube data api
- JavaScript
- getter
- Data Structure
- 포인터 변수
- Redux
- 깃
- GIT
- 알고리즘
- useEffect
- jQuery
- this
- 개발 공부
- til
- Java
- 인스턴스
- 자바
- Prefix Sums
- 제네릭스
- c언어
- Session
- react
- linkedlist
- 리덕스
- package.json
- Conflict
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |