해결하려는 문제
- 일반적으로 데이터는 props를 통해 컴포넌트에 전달됨
- 하지만 props를 통해서 '여러 컴포넌트를 거쳐' 많은 데이터를 전달할 경우에, 그 데이터를 사용하지 않는 컴포넌트에도 그 데이터를 전달하기 위해 props이 쓰임. 앱이 큰 경우에 전달하는 체인이 점점 더 길어질 수 있음
- (eg) login함수. login state는 앱 곳곳에서 필요함
해결책
- props를 실제로 필요한 데이터를 부모로부터 받는 컴포넌트에서'만' 사용하기
- 앱 안에서 전역적으로 사용되는 데이터들을 여러 컴포넌트들끼리 쉽게 공유할 수 있는 방법
- 리액트에 내장된 내부적인 state저장소가 있음 => reactContext(Context API)
- reactContext를 사용하면 그 컴포넌트 전체 state저장소에서 액션을 트리거할 수 있음. 그 후 관련된 컴포넌트에 직접 전달 하 수 있음. 이렇게 하면 props로 데이터를 일일히 전달해(Data drilling) 주지 않아도됨
사용법
- 보통 store, context라는 폴더명으로 관리
- 파일은 컴포넌트가 포함되지 않는다면 파스칼 표기법(AuthContext.js) 대신 케밥 표기법(auth-context.js)으로 표시
- React.createContext()로 context 객체를 만듦
- () 내부에는 객체인 경우가 많음
참고)
const AuthContext = React.createContext({
isLoggedIn: false,
});
1. 공급하기
-리액트에 '여기 내 컨텍스트가 있다'라고 알려줘야함. 그것이 감싸는 모든 컴포넌트는 접근 권한이 있어야함
-그 컨텍스트를 활용할 수 있어야하는 모든 컴포넌트를 JSX코드로 감싼다. 그러면 해당 컨텍스트를 들을 수 있음. 감싸지지 않은 컴포넌트는 리스닝 할 수 없다
-감싼 컴포넌트의 모든 자식 컴포넌트들은 해당 컴포넌트에 접근 할 수 있음
-AuthContext.Provider
return (
<AuthContext.Provider>
<MainHeader isAuthenticated={isLoggedIn} onLogout={logoutHandler} />
<main>
{!isLoggedIn && <Login onLogin={loginHandler} />}
{isLoggedIn && <Home onLogout={logoutHandler} />}
</main>
</AuthContext.Provider>
);
}
2. 소비하기
-React.create() 내부의 값에 접근하기 (리스닝 부분) 2가지 방법
1) AuthContext.Consumer
2) useContext 훅 (일반적인 방법)
1) AuthContext.Consumer
-사용자가 인증되어있는지 여부를 알고 싶다면, JSX로 해당 return문을 AuthContext.Consumer로 감싸기
-소비자는 함수인 자식을 가지고 있음. 매개변수로는 context 데이터를 가짐
const Navigation = (props) => {
return (
<AuthContext.Consumer>
{(ctx) => {
return (
<nav className={classes.nav}>
<ul>
{ctx.isLoggedIn && (
<li>
<a href="/">Users</a>
</li>
)}
{ctx.isLoggedIn && (
<li>
<a href="/">Admin</a>
</li>
)}
{ctx.isLoggedIn && (
<li>
<button onClick={props.onLogout}>Logout</button>
</li>
)}
</ul>
</nav>
);
}}
</AuthContext.Consumer>
);
};
export default Navigation;
2) useContext 훅 (일반적인 방법): Context를 사용하고 리스닝하게 해줌
import React, { useContext } from "react";
import classes from "./Navigation.module.css";
import AuthContext from "../../store/auth-context";
const Navigation = (props) => {
const ctx = useContext(AuthContext);
return (
<nav className={classes.nav}>
<ul>
{ctx.isLoggedIn && (
<li>
<a href="/">Users</a>
</li>
)}
{ctx.isLoggedIn && (
<li>
<a href="/">Admin</a>
</li>
)}
{ctx.isLoggedIn && (
<li>
<button onClick={props.onLogout}>Logout</button>
</li>
)}
</ul>
</nav>
);
};
export default Navigation;
하지만
-Context를 사용하면 컴포넌트를 재사용하기 어려워 질 수 있음
:해당 context의 store를 구독하게됨, 데이터 하나를 결합하여 사용. 다른 컴포넌트와 결합이 되버리면 계속 그 컴포넌트와 연결되니까 (재사용 하려면 props를 사용)
-Prop drilling을 피하기 위한 목적이라면 컴포넌트 합성Component compoisition을 고려해봄
*컴포넌트 합성: props.children 사용. 컴포넌트를 계속 불러오면서 합성할 수 있음.
Context + useReducer 조합이면 Redux와 동일하게 사용할 수 있다
->Flux 패턴
사용하는 곳
로그인시 token, 테마
Context를 공유하는 지점은 Provider이다
공유받은 context를 사용할때는 useContext사용
Consuming context
필요한 context가 바꼈을때만 랜더링 하자. 어떤 context를 바라볼지 정하기
Provider에서 Value를 넘기는 부분을 state처럼 사용할 수 있게 하기위해
*배열도 넣을 수는 있다
-이름을 바꿔야하면 배열로 넘기기
-명시적으로 써야한다 하면 객체로 넘기기
Flux패턴
Dispatch로 바뀜. 이것을 통해서만 상태를 바꿀 수 있다 (useState말고)
dispatch안에 action 함수가 있음-상태변화를 예측하기 쉽게 만들기 위해
Dispatch - action함수 - reducer 로 상태 변하게 함
Redux는 context API에서 flux패턴이 합쳐진 형태이다
출처
React Hooks에 취한다 - useContext + Context API | 리액트 훅스 시리즈
'React' 카테고리의 다른 글
버튼 클릭 시에만 input값 변경하기 (0) | 2022.08.18 |
---|---|
axios put 사용, header 사용법 (0) | 2022.08.17 |
데이터 get하기/데이터에 따라 버튼 색 바꾸기 (0) | 2022.08.16 |
Mock Data 활용법 (0) | 2022.06.25 |
여러개의 input관리 (0) | 2022.05.30 |