useContext?
- context는 리액트 버전에 따라 정말 많이 변경된 API임
한 때는 쓰지 말라고 공식문서에서 말하기까지..
요즘은 React.createContext와 useContext가 나오면서 활발히 사용되고 있음
- Redux를 useContext로 대체하려는 움직임도 보임
useContext 왜 사용하려고??
- 기존에 컴포넌트 간에 데이터를 전달하려면 props를 이용해야 했음
- 만약 A, B, C, D, E 컴포넌트가 있을 때 A에서 E로 데이터를 내려보내주려면
중간 B, C, D 컴포넌트를 거쳐야 함. 엄청난 비효율
시나리오 및 예시 코드
시나리오
- 어떠한 Container에서 데이터가 수정되거나 추가 / 삭제 등 될 때
다른 Container도 변경되어야 함.
이 때 상태가 변경됨을 알릴 flag(상태)가 필요한데 (여기선 isDataUpdate)
너무 해당 상태 값이 너무 깊숙히 있음.
이 때 prop-drilling을 하지 않고 가져오고 싶을 때!
예시 코드
먼저 상태가 저장될 파일을 생성 (Store 느낌의 파일을 생성,
util에다 넣어도 좋고 약간 컴포넌트 느낌이라 다른 곳에 놓아도 될 듯)
import React, { createContext, useState, useMemo } from 'react';
export const TodoContext = createContext({
isDataUpdate: null,
setIsDataUpdate: () => {},
});
const TodoStore = ({ children }) => {
const [isDataUpdate, setIsDataUpdate] = useState(false);
const value = useMemo(() => ({ isDataUpdate, setIsDataUpdate }), [
isDataUpdate,
setIsDataUpdate,
]);
return (
<TodoContext.Provider value={value}>
{children}
</TodoContext.Provider>
);
};
export default TodoStore;
리액트 앱의 최상단 App.js 수정
import React from 'react';
import './App.css';
import TopbarContainer from './containers/topbar/TopbarContainer';
import MainContainer from './containers/main/MainContainer';
import TodoStore from "./lib/utility/TodoStore";
const App = () => {
return (
<TodoStore>
<TopbarContainer />
<MainContainer />
</TodoStore>
);
};
어떠한 Container (CardContainer) 에서 데이터가 수정되거나 추가 / 삭제 등 될 때
TodoContext에 정의해준 setIsDataUpdate 사용하여 IsDataUpdate 업데이트
(여기선 서버로 삭제 요청)
import React, { useState, useEffect, useRef, useContext } from 'react';
import axios from "axios";
import Card from "../../../../components/main/column/card/Card";
import PopupModal from "../../../../components/common/PopupModal";
import { TodoContext } from "../../../../lib/utility/TodoStore";
const CardContainer = ({ title, body, index, columnId, cardId, previousCardId, isZanSang, setColumnData}) => {
const { setIsDataUpdate } = useContext(TodoContext);
const onClickPopupConfirm = () => {
setColumnData((data)=>{
const newData = [...data]
newData[columnId-1].cards = newData[columnId-1].cards.filter((_, i) => i !== index)
return newData;
});
axios.delete(`api/columns/${columnId}/cards/${cardId}`);
setIsDataUpdate(true);
};
return (
<>
<Card data={data} flags={flags} onEvents={onEventsCard} />
<PopupModal />
</>
);
};
export default CardContainer;
변경되어야 하는 다른 Container인 TopbarContainer 수정
import React, { useEffect, useState, useContext } from 'react';
import { TodoContext } from '../../lib/utility/TodoStore';
import { calcPastTime, fetchData } from '../../lib/utility/util';
import TopbarTemplate from '../../components/topbar/TopbarTemplate';
const TopbarContainer = () => {
const { isDataUpdate, setIsDataUpdate } = useContext(TodoContext);
useEffect(() => {
if (isDataUpdate) {
getActivityData();
setIsDataUpdate(false);
}
}, [isDataUpdate, setIsDataUpdate]);
return <TopbarTemplate />
};
export default TopbarContainer;
마지막으로.. useContext 사용 시 주의사항
- useContext를 쓸 때 주의할 사항은, Provider에 제공한 value가 달라지면
useContext를 쓰고 있는 모든 컴포넌트가 리렌더링 된다는 것..
- 지금 value 안에는
isDataUpdate, setIsDataUpdate 들어있는데
앞으로 개수가 더 늘어날 가능성이 높음.
그 중 하나라도 바뀌면 객체로 묶여있으므로 전체가 리렌더링 되어버림..
따라서 잘못 쓰면 엄청난 렉을 유발할 수 있음!!
참고 자료
useContext?
한 때는 쓰지 말라고 공식문서에서 말하기까지..
요즘은 React.createContext와 useContext가 나오면서 활발히 사용되고 있음
useContext 왜 사용하려고??
중간 B, C, D 컴포넌트를 거쳐야 함. 엄청난 비효율
시나리오 및 예시 코드
시나리오
이 때 상태가 변경됨을 알릴 flag(상태)가 필요한데 (여기선
isDataUpdate)너무 해당 상태 값이 너무 깊숙히 있음.
이 때 prop-drilling을 하지 않고 가져오고 싶을 때!
예시 코드
먼저 상태가 저장될 파일을 생성 (Store 느낌의 파일을 생성,
util에다 넣어도 좋고 약간 컴포넌트 느낌이라 다른 곳에 놓아도 될 듯)
리액트 앱의 최상단
App.js수정어떠한 Container (
CardContainer) 에서 데이터가 수정되거나 추가 / 삭제 등 될 때TodoContext에 정의해준
setIsDataUpdate사용하여IsDataUpdate업데이트(여기선 서버로 삭제 요청)
변경되어야 하는 다른 Container인
TopbarContainer수정마지막으로.. useContext 사용 시 주의사항
useContext를 쓰고 있는 모든 컴포넌트가 리렌더링 된다는 것..
isDataUpdate,setIsDataUpdate들어있는데앞으로 개수가 더 늘어날 가능성이 높음.
그 중 하나라도 바뀌면 객체로 묶여있으므로 전체가 리렌더링 되어버림..
따라서 잘못 쓰면 엄청난 렉을 유발할 수 있음!!
참고 자료