useContext란?
특정한 값을 모든 컴포넌트에서 사용할 수 있도록 만들어놓고, 어디서든 만든 값을 불러와서 사용할 수 있도록 해주는 Hook
useContext의 장점
useContext가 없다면 상위 컴포넌트에서 생성한 데이터를 하위 컴포넌트에 전달하기 위해 해당 데이터가 필요하지 않은 여러 컴포넌트를 거치면서 props drilling 현상이 생긴다. useContext를 사용하면 해당 데이터가 필요한 부분에서만 값을 호출해 사용할 수 있다.
하지만 그렇다고 해서 항상 useContext 를 써야하는건 아니다. useContext는 여러 하위 컴포넌트에서 공유되어야 하는 값이 있을 때만 사용하는 것이고, 각 컴포넌트로별로만 관리하는 값이라면 그냥 useState 를 쓰는 것이 더 적절하다.
useContext의 단점
리액트는 state 값이 변하면 해당 state가 있는 컴포넌트를 다시 렌더링 한다. 하지만 context를 사용해 state값을 사용하게 되면 해당 state를 가지고 있지는 않아도 useProvider의 모든 하위 컴포넌트가 전부 다 렌더링이 된다. 즉 렌더링 시간이 훨씬 길어지게 된다.
useContext 사용법
1. createContext 함수로 context 생성
const UserContext = createContext()
2. 생성한 context로 컴포넌트를 감싸주고 value에 하위 컴포넌트가 사용할 값을 전달
UserContext로 감싸진 UserList 컴포넌트와 UserList 컴포넌트의 모든 하위 컴포넌트들은 count 데이터를 쉽게 전달 받을 수 있다.
<UserContext.Provider value={ count: 1 }>
<UserList />
</UserContext.Provider>
3. 만들어 놓은 context를 불러온 후에 useContext 를 써주면 Provider의 value 부분을 통해서 넘겨준 그 값을 받아올 수 있게 된다
import { UserContext } from '../App'
const { count } = useContext(UserContext)
예제 1
App.jsx
가장 최상위 컴포넌트인 App에서 useContext 훅을 사용해서 App의 모든 하위 컴포넌트가 state와 dispatch 데이터에 접근이 가능하도록 한다. 이때 만든 Context는 컴포넌트 밖에서 정의한 후 export해 하위 컴포넌트가 import가 가능하도록 한다.
import React, { createContext, useReducer } from 'react'
import { userData } from './constant/userData'
import { userReducer } from './reducers/userReducer'
import UserList from './components/UserList'
export const UserContext = createContext()
const App = () => {
// const [state, dispatch] = useReducer(리듀서 이름, 초기 데이터)
const [state, dispatch] = useReducer(userReducer, userData)
return (
<UserContext.Provider value={{ state, dispatch }}>
<UserList />
</UserContext.Provider>
)
}
export default App
UserList.jsx
import React, { useContext, useRef, useState } from 'react'
import { UserContext } from '../App'
const UserList = () => {
const [userInput, setUserInput] = useState({
id: '',
name: '',
email: '',
})
const userInputHandler = (e) => {
const { name, value } = e.target
setUserInput({
...userInput,
[name]: value,
})
}
const userId = useRef(11)
const { state, dispatch } = useContext(UserContext)
const addUser = (userInput) => {
dispatch({
type: 'ADD',
data: { ...userInput, id: userId.current },
})
userId.current += 1
}
const removeUser = (userId) => {
dispatch({
type: 'REMOVE',
data: { id: userId },
})
}
return (
<>
<div>
{state.map((user) => (
<div key={user.id}>
<p>{user.name}</p>
<button onClick={() => removeUser(user.id)}>제거하기</button>
</div>
))}
</div>
<input
type="text"
name="name"
placeholder="name"
onChange={userInputHandler}
/>
<input
type="email"
name="email"
placeholder="email"
onChange={userInputHandler}
/>
<button onClick={() => addUser(userInput)}>이름 추가</button>
</>
)
}
export default UserList
예제 2
context 관련 로직 컴포넌트에서 사용하지 않고 따로 빼주기
UserContext.js
import React, { createContext, useReducer } from 'react'
import { userData } from '../constant/userData'
import { userReducer } from '../reducers/userReducer'
export const UserContext = createContext()
export function UserProvider({ children }) {
const [state, dispatch] = useReducer(userReducer, userData)
return (
<UserContext.Provider value={{ state, dispatch }}>
{children}
</UserContext.Provider>
)
}
App.jsx
import React from 'react'
import { UserProvider } from './contexts/UserContext'
import UserList from './components/UserList'
const App = () => {
return (
<UserProvider>
<UserList />
</UserProvider>
)
}
export default App
UserList.jsx
import React, { useContext, useRef, useState } from 'react'
import { UserContext } from '../contexts/UserContext'
const UserList = () => {
const [userInput, setUserInput] = useState({
id: '',
name: '',
email: '',
})
const userInputHandler = (e) => {
const { name, value } = e.target
setUserInput({
...userInput,
[name]: value,
})
}
const userId = useRef(11)
const { state, dispatch } = useContext(UserContext)
const addUser = (userInput) => {
dispatch({
type: 'ADD',
data: { ...userInput, id: userId.current },
})
userId.current += 1
}
const removeUser = (userId) => {
dispatch({
type: 'REMOVE',
data: { id: userId },
})
}
return (
<>
<div>
{state.map((user) => (
<div key={user.id}>
<p>{user.name}</p>
<button onClick={() => removeUser(user.id)}>제거하기</button>
</div>
))}
</div>
<input
type="text"
name="name"
placeholder="name"
onChange={userInputHandler}
/>
<input
type="email"
name="email"
placeholder="email"
onChange={userInputHandler}
/>
<button onClick={() => addUser(userInput)}>이름 추가</button>
</>
)
}
export default UserList
'React' 카테고리의 다른 글
[리액트] 컴포넌트 렌더링시 useEffect 한번만 실행되도록 바꿔주기 (0) | 2022.08.23 |
---|---|
[리액트] useEffect 4가지 사용법 간단 정리 (0) | 2022.08.23 |
[리액트] useReducer 사용법 (0) | 2022.08.21 |
[리액트] 리액트에서 스타일 적용하는 5가지 방법 (인라인 스타일, CSS, SCSS, CSS Module, Styled-Components) (0) | 2022.08.12 |
[리액트] props를 className으로 지정하기 (0) | 2022.08.12 |
댓글