반응형
React Context
리액트의 하나의 컴포넌트에서 데이터를 생성하거나 업데이트하거나 다른 컴포넌트와 데이터를 공유해서 사용하는 여러 방법이 있습니다.
- state 와 props를 사용해서 컴포넌트 간에 데이터를 전달
- React Context API를 사용해서 컴포넌트 간에 데이터를 전달
- Redux, MobX, Recoil 등의 상태 관리 라이브러리를 사용
Context API란
- React Context는 Component 트리 전체에 props를 전달하지 않고도 Component 데이터를 제공하는 방법입니다.
- Context는 전역 상태를 관리하기 위한 간단한 방법입니다.
Context 문법
React.createContext
함수를 사용하여Context
를 생성합니다.Context.Provider
컴포넌트를 만나면,value
prop을 통해Context
의 값을 제공합니다.Context.Consumer
컴포넌트를 사용하여Context
의 값을 사용합니다.
Context 사용하기
React.createContext
함수를 사용하여 Context를 생성합니다.
const MyContext = React.createContext(defaultValue)
Context.Provider
컴포넌트를 사용하여 Context를 제공합니다.
<MyContext.Provider value={/* 상태 값 */}>
{/* 여기에 위치한 컴포넌트들은 이 Context의 값을 사용할 수 있음 */}
</MyContext.Provider>
Context.Consumer
컴포넌트를 사용하여 Context를 사용합니다.
<MyContext.Consumer>
{value => /* 상태 값에 따라 UI를 렌더링 */}
</MyContext.Consumer>
Context를 사용한 Theme 예제
const themes = {
light: {
foreground: '#000000',
background: '#eeeeee',
},
dark: {
foreground: '#ffffff',
background: '#222222',
},
}
// createContext 함수를 사용하여 Context 생성
const ThemeContext = React.createContext(themes.light)
function App() {
return (
// context value를 공유할 컴포넌트를 감싸기
// 공유하기 위한 value를 설정
<ThemeContext.Provider value={themes.dark}>
<Toolbar />
</ThemeContext.Provider>
)
}
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
)
}
function ThemedButton() {
// context value를 사용하기 위해 useContext hook 사용
const theme = useContext(ThemeContext)
return (
<button style={{ background: theme.background, color: theme.foreground }}>I am styled by theme context!</button>
)
}
export default App
Context를 이용한 앱 만들기
- 주문 페이지
여러 컴포넌트의 가격과 옵션을 공유하여 총액을 계산하여 보여주는 페이지를 만들어보겠습니다.
const OrderContext = React.createContext()
function App() {
const [order, setOrder] = useState({
price: 0,
option: 'none',
})
return (
<OrderContext.Provider value={{ order, setOrder }}>
<Order />
<Total />
</OrderContext.Provider>
)
}
function Order() {
const { order, setOrder } = useContext(OrderContext)
const handleChange = (e) => {
setOrder({ ...order, option: e.target.value })
}
return (
<div>
<h1>Order</h1>
<select value={order.option} onChange={handleChange}>
<option value="none">None</option>
<option value="sugar">Sugar</option>
<option value="milk">Milk</option>
</select>
</div>
)
}
function Total() {
const { order } = useContext(OrderContext)
return (
<div>
<h1>Total</h1>
<p>Price: {order.price}</p>
<p>Option: {order.option}</p>
</div>
)
}
export default App
전세계 나라의 현재 시간을 보여주는 Context 예제
// TimeContext.js
import React, { createContext } from 'react'
// Context 생성
const TimeContext = createContext()
export default TimeContext
// TimeApp.js
import React, { useState } from 'react'
import TimeContext from './TimeContext'
function TimeApp() {
const [time, setTime] = useState(new Date())
const updateTime = () => {
setTime(new Date()) // 현재 시간으로 업데이트
}
return (
// Context.Provider로 전역 상태를 제공
<TimeContext.Provider value={time}>
<div>
<h1>전세계 나라의 현재 시간</h1>
<button onClick={updateTime}>시간 업데이트</button>
<Time />
</div>
</TimeContext.Provider>
)
}
function Time() {
return (
// Context.Consumer로 전역 상태를 사용
<TimeContext.Consumer>
{(time) => (
<div>
<p>한국: {time.toLocaleString('ko-KR')}</p>
<p>미국: {time.toLocaleString('en-US')}</p>
<p>중국: {time.toLocaleString('zh-CN')}</p>
</div>
)}
</TimeContext.Consumer>
)
}
export default TimeApp
Context API 활용한 날씨 앱 만들기
- 날씨 API를 사용하여 날씨 정보를 가져옵니다.
- 날씨 API 사용법
// WeatherContext.js
import React, { createContext, useState, useEffect } from 'react'
const WeatherContext = createContext()
export function WeatherProvider({ children }) {
const [weather, setWeather] = useState(null)
useEffect(() => {
fetch('https://api.openweathermap.org/data/2.5/weather?q=seoul&appid=YOUR_API_KEY&units=metric')
.then((res) => res.json())
.then((data) => {
setWeather(data)
})
}, [])
return <WeatherContext.Provider value={weather}>{children}</WeatherContext.Provider>
}
export default WeatherContext
// WeatherApp.js
import React from 'react'
import WeatherContext, { WeatherProvider } from './WeatherContext'
function WeatherApp() {
return (
<WeatherProvider>
<div>
<h1>날씨 앱</h1>
<Weather />
</div>
</WeatherProvider>
)
}
function Weather() {
return (
<WeatherContext.Consumer>
{(weather) => (
<div>
{weather ? (
<div>
<p>도시: {weather.name}</p>
<p>날씨: {weather.weather[0].main}</p>
<p>온도: {weather.main.temp}°C</p>
</div>
) : (
<p>날씨 정보를 가져오는 중...</p>
)}
</div>
)}
</WeatherContext.Consumer>
)
}
export default WeatherApp
- 할 일 관리 앱 Context API 사용하기
// src/context/TodoContext.js
import React, { createContext, useReducer, useContext } from 'react'
// 초기 상태
const initialState = [
{
id: 1,
isDone: false,
task: '고양이 밥주기',
createdDate: new Date().getTime(),
},
{
id: 2,
isDone: false,
task: '감자 캐기',
createdDate: new Date().getTime(),
},
{
id: 3,
isDone: false,
task: '고양이 놀아주기',
createdDate: new Date().getTime(),
},
]
// reducer 함수
function reducer(state, action) {
switch (action.type) {
case 'ADD':
return [action.payload, ...state]
case 'UPDATE':
return state.map((it) => (it.id === action.payload ? { ...it, isDone: !it.isDone } : it))
case 'DELETE':
return state.filter((it) => it.id !== action.payload)
default:
return state
}
}
// Context 객체 생성
const TodoStateContext = createContext()
const TodoDispatchContext = createContext()
// 커스텀 훅 생성
export function useTodoState() {
return useContext(TodoStateContext)
}
export function useTodoDispatch() {
return useContext(TodoDispatchContext)
}
// Provider 컴포넌트 생성
export function TodoProvider({ children }) {
const [state, dispatch] = useReducer(reducer, initialState)
return (
<TodoStateContext.Provider value={state}>
<TodoDispatchContext.Provider value={dispatch}>{children}</TodoDispatchContext.Provider>
</TodoStateContext.Provider>
)
}
// src/components/App.js
import React from 'react'
import TodoHd from './TodoHd'
import TodoEditor from './TodoEditor'
import TodoList from './TodoList'
import { TodoProvider } from '../context/TodoContext'
function App() {
return (
<TodoProvider>
<div>
<TodoHd />
<TodoEditor />
<TodoList />
</div>
</TodoProvider>
)
}
export default App
// src/components/TodoList.js
import React, { useState } from 'react'
import TodoItem from './TodoItem'
import { useTodoState, useTodoDispatch } from '../context/TodoContext'
export default function TodoList() {
const todo = useTodoState()
const dispatch = useTodoDispatch()
const [search, setSearch] = useState('')
const onChangeSearch = (e) => {
setSearch(e.target.value)
}
const filteredTodo = () => {
return todo.filter((item) => item.task.toLowerCase().includes(search.toLowerCase()))
}
return (
<div>
<h2>할 일 목록 📃</h2>
<input value={search} onChange={onChangeSearch} placeholder="검색어를 입력하세요" />
<ul>
{filteredTodo().map((item) => (
<TodoItem key={item.id} {...item} />
))}
</ul>
</div>
)
}
// src/components/TodoEditor.js
import React, { useState } from 'react'
import { useTodoDispatch } from '../context/TodoContext'
export default function TodoEditor() {
const dispatch = useTodoDispatch()
const [task, setTask] = useState('')
const onChangeTask = (e) => {
setTask(e.target.value)
}
const onSubmit = () => {
if (!task) {
return
}
dispatch({ type: 'ADD', payload: { id: Date.now(), isDone: false, task, createdDate: new Date().getTime() } })
setTask('')
}
const onKeyDown = (e) => {
if (e.key === 'Enter') {
onSubmit()
}
}
return (
<div className="TodoEditor">
<h2>새로운 Todo 작성하기 ✏ </h2>
<div>
<input
value={task}
onChange={onChangeTask}
onKeyDown={onKeyDown}
placeholder="할 일을 추가로 입력해주세요."
/>
<button onClick={onSubmit}>추가</button>
</div>
</div>
)
}
// src/components/TodoItem.js
import React from 'react'
import { useTodoDispatch } from '../context/TodoContext'
export default function TodoItem({ id, isDone, task, createdDate }) {
const dispatch = useTodoDispatch()
const onUpdate = () => {
dispatch({ type: 'UPDATE', payload: id })
}
const onDelete = () => {
dispatch({ type: 'DELETE', payload: id })
}
return (
<div>
<li key={id}>
<input type="checkbox" checked={isDone} onChange={onUpdate} />
<span style={{ textDecoration: isDone ? 'line-through' : 'none' }}>{task}</span>
<span>{new Date(createdDate).toLocaleDateString()}</span>
<button onClick={onDelete}>삭제</button>
</li>
</div>
)
}
반응형
'Front > React' 카테고리의 다른 글
리액트 ES6 문법 정리 - 기본편 (0) | 2024.03.29 |
---|---|
쉽게 배우는 리액트(React.js) 앱 제작 실무 (0) | 2024.03.24 |
타입스크립트 개요 및 개발 환경 구성 (0) | 2024.03.19 |
useReducer - React 배우기 (0) | 2024.03.19 |
최적화 - React 배우기 (0) | 2024.03.18 |