1. 컨텍스트 만들기
const stateContext = createContext(null)
<stateContext.Provider value = {state}>
<App/>
</stateContext.Provider>
2. 컨텍스트 사용하기
const state = useContext(stateContext)
TS-REACT-TUTORIAL

SampleContext.tsx
import React, { createContext, Dispatch, useContext, useReducer } from 'react';
type Color = 'red' | 'orange' | 'green'
type State = {
count: number;
text: string;
color: Color;
isGood: boolean
}
type Action = {type: 'SET_COUNT'; count: number}
| {type: 'SET_TEXT'; text: string}
| {type: 'SET_COLOR'; color: Color}
| {type: 'TOGGLE_GOOD'}
// 디스패치를 위한 타입 (Dispatch)
type SampleDispatch = Dispatch<Action>
// Context 만들기
const SampleStateContext = createContext<State | null>(null)
const SampleDispatchContext = createContext<SampleDispatch | null>(null)
function reducer(state: State, action: Action) : State {
switch(action.type) {
case 'SET_COUNT':
return {
...state,
count: action.count
}
case 'SET_TEXT':
return {
...state,
text: action.text
}
case 'SET_COLOR':
return {
...state,
color: action.color
}
case 'TOGGLE_GOOD':
return {
...state,
isGood: !state.isGood
}
default:
throw new Error('액션이 없어요')
}
}
export function SampleProvider({children}:{children:React.ReactNode}) {
const [state, dispatch] = useReducer(reducer, {
count: 0,
text: 'Hello',
color: 'red',
isGood: true
});
return (
<SampleStateContext.Provider value = {state}>
<SampleDispatchContext.Provider value={dispatch}>
{children}
</SampleDispatchContext.Provider>
</SampleStateContext.Provider>
)
}
// state와 dispatch를 쉽게 사용하기위한 커스텀 hook
export function useSampleState() {
const state = useContext(SampleStateContext);
if(!state) throw new Error('찾을 수 없어') // 유효하지 않을 땐 에러를 발생
return state
}
export function useSampleDispatch() {
const dispatch = useContext(SampleDispatchContext);
if(!dispatch) throw new Error('찾을 수 없어') // 유효하지 않을 땐 에러를 발생
return dispatch
}
ReducerSample.tsx
import React, { useReducer } from 'react';
import { useSampleDispatch, useSampleState } from './SampleContext';
// 기존 useReducer
// 이제 SampleContext로부터 받아온 것을 사용해서 다 주석처리함
// type Color = 'red' | 'orange' | 'green'
// type State = {
// count: number;
// text: string;
// color: Color;
// isGood: boolean
// }
// type Action = {type: 'SET_COUNT'; count: number}
// | {type: 'SET_TEXT'; text: string}
// | {type: 'SET_COLOR'; color: Color}
// | {type: 'TOGGLE_GOOD'}
// function reducer(state: State, action: Action) : State {
// switch(action.type) {
// case 'SET_COUNT':
// return {
// ...state,
// count: action.count
// }
// case 'SET_TEXT':
// return {
// ...state,
// text: action.text
// }
// case 'SET_COLOR':
// return {
// ...state,
// color: action.color
// }
// case 'TOGGLE_GOOD':
// return {
// ...state,
// isGood: !state.isGood
// }
// default:
// throw new Error('액션이 없어요')
// }
// }
const ReducerSample = () => {
// const [state, dispatch] = useReducer(reducer, {
// count: 0,
// text: 'Hello',
// color: 'red',
// isGood: true
// });
const state = useSampleState();
const dispatch = useSampleDispatch();
const setCount = () => dispatch({ type: 'SET_COUNT', count:5 })
const setText = () => dispatch({ type:'SET_TEXT', text: 'bye' })
const setColor = () => dispatch({ type: 'SET_COLOR', color: 'orange' })
const toggleGood = () => dispatch({ type:'TOGGLE_GOOD' })
return (
<div>
<p>
<code>count : </code> {state.count}
</p>
<p>
<code>text : </code> {state.text}
</p>
<p>
<code>color : </code> {state.color}
</p>
<p>
<code>isGood : </code> {state.isGood? 'true' : 'false'}
</p>
<div>
<button onClick={setCount}>setcount</button>
<button onClick={setText}>setText</button>
<button onClick={setColor}>setcolor</button>
<button onClick={toggleGood}>toggleGood</button>
</div>
</div>
);
};
export default ReducerSample;
App.tsx
import React, { useReducer } from 'react';
import './App.css';
// import CreateTodo from './CreateTodo';
import Counter from './Counter';
import Counter_Reduce from './Counter_Reduce';
import ReducerSample from './ReducerSample';
import MyForm from './MyForm';
import { SampleProvider } from './SampleContext';
function App() {
return (
<div className="App">
{/* <Counter /> */}
{/* <MyForm /> */}
{/* <Counter_Reduce /> */}
<SampleProvider>
<ReducerSample/>
</SampleProvider>
</div>
);
}
export default App;

todosContext.tsx
import React, { createContext, useReducer, Dispatch, useContext } from 'react';
// 상태 관리할 데이터
// 1. input의 값
// 2. 할 일 목록
export type Todo = {
id: number;
text: string;
isDone: boolean;
}
type State = {
inputText: string;
todos: Todo[]
}
// 액션
// input 값이 변경될 때 inputText 변경- INPUT_CHANGE
// 등록버튼 누르면 할 일 추가 - CREATE_TODO
// 삭제버튼 누르면 할 일 삭제 - DELETE_TODO
// 할 일 항목 클릭시 isDone 값을 반전 - DONE_TODO
type Action = { type: 'INPUT_CHANGE'; inputText: string }
| { type: 'CREATE_TODO'; todo: Todo }
| { type: 'DELETE_TODO'; id: number }
| { type: 'DONE_TODO'; id: number }
type TypeDispatch = Dispatch<Action>
// Context 만들기
const todoStateContext = createContext<State|null>(null);
const todoDispatchContext = createContext<TypeDispatch|null>(null);
function reducer(state:State, action: Action) :State {
switch(action.type) {
case 'INPUT_CHANGE':
console.log(state.inputText)
return {
...state,
inputText: action.inputText
}
case 'CREATE_TODO':
return {
...state,
todos: [
...state.todos,
action.todo
]
}
case 'DELETE_TODO':
return {
...state,
todos: state.todos.filter(todo=> todo.id !== action.id)
}
case 'DONE_TODO':
return {
...state,
todos: state.todos.map(todo=> todo.id === action.id
? {...todo, isDone: !todo.isDone } : todo)
}
default:
throw new Error("액션이 없어요")
}
}
// todoStateContext state를 지정
// todoDispatchContext dispatch를 지정
export function TodoContext({children}: {children: React.ReactNode}) {
const [state, dispatch]=useReducer(reducer, {
inputText: "",
todos: [{
id: 1,
text: "타입스크립트 공부",
isDone: false
},{
id: 2,
text: "리덕스 공부",
isDone: false
}]
})
return (
<todoStateContext.Provider value={state}>
<todoDispatchContext.Provider value={dispatch}>
{children}
</todoDispatchContext.Provider>
</todoStateContext.Provider>
)
}
// state와 dispatch를 쉽게 사용하기 위한 커스텀hooks
export function useTodoState() {
const state = useContext(todoStateContext);
if (!state) throw new Error("유효하지 않음")
return state;
}
export function useTodoDispatch() {
const dispatch = useContext(todoDispatchContext);
if (!dispatch) throw new Error("유효하지 않음")
return dispatch;
}
components/TodoList.tsx
import React from 'react';
import { Todo } from '../todosContext'
type TodoProps = {
todos: Todo [];
onDelete(id:number):void;
onToggle(id:number):void;
}
const TodoList = ( {todos, onDelete, onToggle} : TodoProps ) => {
return (
<div>
<ul>
{todos.map(todo=> <li key={todo.id} className={todo.isDone? "active": ""}><span onClick={()=>onToggle(todo.id)}>{todo.text}</span><button onClick={()=>onDelete(todo.id)}>삭제</button></li>)}
{/* key 안줘서 나는 오류 key={todo.id} 추가하기 */}
</ul>
</div>
);
};
export default TodoList;
components/InsertTodo.tsx
import React from 'react';
type InsertProps = {
inputText: string;
onChange(text:string): void;
onCreate(): void
}
const InsertTodo = ({ inputText, onChange, onCreate } : InsertProps) => {
return (
<div>
<input value={inputText} onChange={(e)=>onChange(e.target.value)}/>
<button onClick={onCreate}>등록</button>
</div>
);
};
export default InsertTodo;
App3.tsx
import React, { useRef } from 'react';
import { useTodoDispatch, useTodoState } from './todosContext';
import InsertTodo from './components/InsertTodo';
import TodoList from './components/TodoList';
import './App.css';
// 상태 관리할 데이터
// 1. input의 값
// 2. 할 일 목록
// export type Todo = {
// id: number;
// text: string;
// isDone: boolean;
// }
// type State = {
// inputText: string;
// todos: Todo[]
// }
// // 액션
// // input 값이 변경될 때 inputText 변경- INPUT_CHANGE
// // 등록버튼 누르면 할 일 추가 - CREATE_TODO
// // 삭제버튼 누르면 할 일 삭제 - DELETE_TODO
// // 할 일 항목 클릭시 isDone 값을 반전 - DONE_TODO
// type Action = { type: 'INPUT_CHANGE'; inputText: string }
// | { type: 'CREATE_TODO'; todo: Todo }
// | { type: 'DELETE_TODO'; id: number }
// | { type: 'DONE_TODO'; id: number }
// function reducer(state:State, action: Action) :State {
// switch(action.type) {
// case 'INPUT_CHANGE':
// console.log(state.inputText)
// return {
// ...state,
// inputText: action.inputText
// }
// case 'CREATE_TODO':
// return {
// ...state,
// todos: [
// ...state.todos,
// action.todo
// ]
// }
// case 'DELETE_TODO':
// return {
// ...state,
// todos: state.todos.filter(todo=> todo.id !== action.id)
// }
// case 'DONE_TODO':
// return {
// ...state,
// todos: state.todos.map(todo=> todo.id === action.id
// ? {...todo, isDone: !todo.isDone } : todo)
// }
// default:
// throw new Error("액션이 없어요")
// }
// }
const App3 = () => {
// const [state, dispatch] = useReducer(reducer, {
// inputText: "",
// todos: [{
// id: 1,
// text: "타입스크립트 공부",
// isDone: false
// },{
// id: 2,
// text: "리덕스 공부",
// isDone: false
// }]
// })
const idNum = useRef(2);
const state = useTodoState();
const dispatch = useTodoDispatch();
const { inputText, todos } = state;
const onChange = (text: string) => dispatch({ type: 'INPUT_CHANGE', inputText: text })
const onCreate = () => {
idNum.current++;
console.log(idNum.current)
dispatch({type:'CREATE_TODO', todo: {
id: idNum.current,
text: state.inputText,
isDone: false
}})
}
const onDelete = (id: number) => dispatch({ type: 'DELETE_TODO', id: id})
const onToggle = (id: number) => dispatch({ type: 'DONE_TODO', id: id})
return (
<div>
<InsertTodo inputText={inputText} onChange={onChange} onCreate={onCreate}/>
<TodoList todos={todos} onDelete={onDelete} onToggle={onToggle}/>
</div>
);
};
export default App3;
App.css
.active {
background-color: antiquewhite;
}
index.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import reportWebVitals from './reportWebVitals';
// import App from './App';
// import App2 from './App2';
import App3 from './App3';
import { TodoContext } from './todosContext';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
{/* <App /> */}
{/* <App2 /> */}
<TodoContext>
<App3 />
</TodoContext>
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
'Stack > TypeScript' 카테고리의 다른 글
[TS / React] Redux로 To-do List 구현 (0) | 2022.07.29 |
---|---|
[TS / React] Redux로 Counter 구현 (0) | 2022.07.28 |
[TS / React] To-Do List 구현 (0) | 2022.07.27 |
[TS / React] props 전달 (0) | 2022.07.27 |
[TS / React] React에서 TS 사용해보기 2 (useReducer) (0) | 2022.07.27 |