- useContext 필요성
기존 props를 사용하여 데이터를 전달 할 땐 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달했는데, prop drilling 현상으로 인해서 props가 어떤 컴포넌트로 부터 왔는지 파악이 어려워진다. 또한 오류가 발생 시 추적이 힘들어져서 대처도 늦게 되는데, 이걸 해결 해주는 API 가 useContext 다.
useContext 미사용 시
import "./App.css";
import GrandFather from "./components/GrandFather";
export function App() {
return <GrandFather />;
}
export default App;
import React from "react";
import Father from "./Father";
function GrandFather() {
const grandFatherName = "마동석";
const pocketMoney = 50000;
return <Father grandFatherName={grandFatherName} pocketMoney={pocketMoney} />;
}
export default GrandFather;
import React from "react";
import Child from "./Child";
function Father({ grandFatherName, pocketMoney }) {
return <Child grandFatherName={grandFatherName} pocketMoney={pocketMoney} />;
}
export default Father;
import React from "react";
function Child({ grandFatherName, pocketMoney }) {
const stressedWord = {
color: "#9370DB",
fontWeight: "900",
};
return (
<div>
우리 할아버지의 성함은 <span style={stressedWord}>{houseName}</span> 이다.
<br />
할아버지께서 용돈을 <span style={stressedWord}>{pocketMoney}</span> 원이나
주셨다.
</div>
);
}
export default Child;
- 결과 : 우리 할아버지의 성함은 마동석 이다. 할아버지께서 용돈을 50000원이나 주셨다.
useContext 사용 시
import { createContext } from "react";
export const FamilyContext = createContext(null);
import React from "react";
import Father from "./Father";
import { FamilyContext } from "../context/FamilyContext";
function GrandFather() {
const grandFatherName = "마동석";
const pocketMoney = 50000;
return (
<FamilyContext.Provider value={{ grandFatherName, pocketMoney }}>
<Father />
</FamilyContext.Provider>
);
}
export default GrandFather;
import React from "react";
import Child from "./Child";
function Father() {
return <Child />;
}
export default Father;
import React, { useContext } from "react";
import { FamilyContext } from "../context/FamilyContext";
function Child({ grandFatherName, pocketMoney }) {
const stressedWord = {
color: "red",
fontWeight: "900",
};
const data = useContext(FamilyContext);
console.log("data", data);
return (
<div>
우리 할아버지의 성함은 <span style={stressedWord}>{data.grandFatherName}</span> 이다.
<br />
할아버지께서 용돈을 <span style={stressedWord}>{data.pocketMoney}</span> 원이나
주셨다.
</div>
);
}
export default Child;
- 결과 : 우리 할아버지의 성함은 마동석 이다. 할아버지께서 용돈을 50000원이나 주셨다.
위처럼 useContext 를 사용 시 중간 컴포넌트에서 복잡한 과정을 거치지 않고 최종적으로 전달하고 싶은 컴포넌트에 데이터를 전달 할 수 있다.
- 주의사항
useContext를 사용할 때, Provider에서 제공한 value가 달라진다면 useContext를 사용하고 있는 모든 컴포넌트가 리렌더링 된다. 따라서 value 부분을 항상 신경써줘야 한다.
- 최적화
리렌더링이 발생하는 3가지
1. 컴포넌트에서 state가 바뀌었을 때
2. 컴포넌트가 내려받은 props가 변경되었을 때
3. 부모 컴포넌트가 리-렌더링 된 경우 자식 컴포넌트 모두
리렌더링이 자주 발생하는건 그만큼 비용이 발생한다는 의미이기 때문에 최소화 해야한다. 이 때 하는 작업을 "최적화(Optimization)" 라고 한다.
대표적으로 최적화 하는 방법
1. memo(React.memo) : 컴포넌트를 캐싱
2. useCallback : 함수를 캐싱
3. useMemo : 값을 캐싱
- memo(React.memo)
리렌더링 발생 조건 중 3번째인 부모 컴포넌트가 리렌더링 될 때 자식 컴포넌트 모두 리렌더링 되는 상황을 해결해준다.
- memo(React.memo)
useCallback 은 인자로 들어오는 함수 자체를 기억한다.
- memo(React.memo)
맨 처음 해당 값을 반환할 때 그 값을 특별한 곳(메모리)에 저장해서 필요할 때 마다 함수를 호출해서 계산하는것이 아닌 이미 저장한 값 을 꺼내와서 쓸 수 있게 해준다.
그러나 useMemo를 남발하게 되면 별도의 메모리 확보를 너무나 많이 하게 되기 때문에 오히려 성능이 악화될 수 있기때문에 필요시에만 사용해야 한다.