TIL74. 형제 컴포넌트의 데이터 전송(with Context API)

조연정·2021년 2월 8일
3
post-thumbnail

형제 컴포넌트 간의 상태 전달을 Context API를 통해 실현해보자.

내가 원하는 작업은 형제 컴포넌트(quiz, result) 간의 데이터 전송이고, 검색해 본 결과 전역상태관리를 할 수 있게 해주는 context api를 사용해야 한다는 것을 알게 되었다.

Context API란?

전역상태관리로 유명한 리덕스와 마찬가지로 글로벌하게 상태관리가 가능하다. Context ApI는 따로 설치하지 않아도 리액트에서 기본으로 지원하는 API기 때문에 호출해서 쓰기만 하면된다.

*Context API vs Redux

Context는 수단일 뿐 상태관리 자체는 useState와 useReducer 로 하게 된다.
리덕스와의 주요 차이는 '성능'이다.

Redux는 컴포넌트에서 전역상태의 특정 값을 의존하게 될 때 해당 값이 바뀔 때에만 리렌더링이 되도록 최적화가 되어있기 때문에 전역상태 중 의존하지 않는 값이 바뀌게 될 때에는 컴포넌트에서 낭비 렌더링이 발생하지 않게된다.

반면 Context에는 성능 최적화가 이뤄지지 않는다. 컴포넌트에서 만약 Context의 특정 값을 의존하는 경우, 해당 값 이외에 다른 값이 변경 될 때에도 컴포넌트에서는 리렌더링이 발생한다.
따라서, 서로 관련이 없는 상태라면 같은 Context를 따로 만들어줘야한다.

context API 사용하기

1.context 폴더 만들기

src폴더 안에 Contexts폴더를 만들고, 그 안에 ButtonContext.tsx 파일을 생성한다.
전역으로 관리할 state를 모아놓을 provider(store).

// context.js
import { createContext, useContext, useState } from 'react';

export const ResultContext = createContext(undefined); 
// createContext 선언

export function ResultContextProvider({ children }) {
	const [result, setResult] = useState([]); ////글로벌하게 관리할 state

	const value = {
		result,
		setResult,
	};

	return <ResultContext.Provider value={value}>{children}</ResultContext.Provider>;
}

export function useResultContext() {
	return useContext(ResultContext);
} //다른 컴포넌트에서 context를 사용할 때 쓰임. 

2.부모컴포넌트에 provider 불러오기

가장 최상단 컴포넌트인 Routes.js 컴포넌트에서 ResultContextProvider를 불러와서 기존 내용을 감싸주어야 한다. 부모 컴포넌트에 두 형제가 접근 가능하기 때문에 부모 컴포넌트에 provider를 불러와야 하는 것.

import { ResultContextProvider } from './Contexts/ResultContext'; //provider 불러오기

function Routes() {
	return (
		<ResultContextProvider> //컴포넌트 감싸주기
				<Router>
					<Switch>
						<Route exact path="/" component={Main} />
						<Route exact path="/quiz" component={Quiz} />
						<Route exact path="/result" component={Result} />
					</Switch>
				</Router>
		</ResultContextProvider>
	);
}

3. 필요한 컴포넌트에서 state 가져와서 사용하기

context에 입력했던 state를 useContext로 사용할 컴포넌트로 가져온다.

//Result.js
import {useResultContext } from '../../Contexts/ResultContext';
// useContext 가져오기

function Result() {
	const { result } = useResultContext();
  
	return (
		<ResultWrapper>
			{result.map((dog, idx) => {
				return (
					<Card
						key={idx}
						img={dog.img}
						name={dog.name}
						averageSize={dog.averageSize}
						description={dog.description}
					/>
				);
			})}
		</ResultWrapper>
	);
}
// Quiz.js 자식 button.js
import { useResultContext } from '../../Contexts/ResultContext';

function Button({ id, question, symbol, selections, number, setNumber }) {
	const [userAnswers, setUserAnswers] = useState({});
	const { setResult } = useResultContext();

	const checkAnswer = (QId: number, AId: number) => {
		const key = QId;
		const obj = { [`${key}`]: AId };
		setUserAnswers({ ...userAnswers, ...obj });
		if (QId === 10) {
			axios
				.post(ANSWERAPI, userAnswers)
				.then((res) => {
					setResult(res.data);
				})
				.catch((error) => console.log(error));
		}
	};
profile
Lv.1🌷

0개의 댓글