728x90
반응형
useReducer 알아보기
2023.01.14 - [react] - [React] Hook 함수정리3(useReducer)
contextAPI 알아보기
2023.01.10 - [react] - [React]Hooks함수 정리1(useState, useRef, useEffect, useContext)
실습연습
context 폴더 안에
SampleContext.tsx
import React, { Children, Dispatch, useContext, useReducer } from 'react';
import { createContext } from 'react';
//필요한 타입 선언
type Color = "red" | "pink" | "yellow";
//상태를 위한 타입
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: "SET_GOOD"}
//디스패치를 위한 타입(Dispatch를 리액트에서 불러올수 있음)
// 액션들의 타입을 Dispatch 제네릭으로 지정
type SampleDispatch = Dispatch<Action>;
//context 생성하기
const SampleStateContext = createContext<State | null>(null);
const SampleDispatchContext = createContext<SampleDispatch | null>(null);
//리듀서 ---- 매개변수 state와 action 타입 지정, 리턴하는 타입을 지정
function reducer(state: State, action:Action): State {
switch(action.type) {
case "SET_COUNT":
return {
...state,
count: action.count
};
case "SET_COLOR":
return {
...state,
color: action.color
};
case "SET_TEXT":
return {
...state,
text: action.text
};
case "SET_GOOD":
return {
...state,
isGood: !state.isGood
};
default:
return state
}
}
/* interface SampleContextProps {
children: React.ReactNode
} */ //인터페이스 안만들고 객체로 바로 넣음(인터페이스로 만들어도됨)
const SampleContext = ({children}:{children: React.ReactNode}) => { //children : 타입지정
const [state, dispatch] = useReducer(reducer, {
count: 0,
color: "pink",
text: "typescript",
isGood: true
})
return (
<SampleStateContext.Provider value={state}>
<SampleDispatchContext.Provider value={dispatch}>
{children}
</SampleDispatchContext.Provider>
</SampleStateContext.Provider>
);
};
export default SampleContext;
//state 와 dispatch 를 사용하기 위한 커스텀 hooks
export function useSampleState(){
const state =useContext(SampleStateContext)
return state;
}
export function useSampleDispatch(){
const dispatch = useContext(SampleDispatchContext)
if(!dispatch) throw new Error("유효하지 않습니다")
// 유효하지 않을때 에러 발생
return dispatch
}
components폴더 안에
ReducerSampleEdit.tsx
import React from 'react';
import { useSampleDispatch, useSampleState } from '../context/SampleContext';
const ReducerSampleEdit = () => {
const state = useSampleState()
const dispatch = useSampleDispatch()
const setCount = () => {
dispatch({type: "SET_COUNT", count: 5})
}
const setText = () => {
dispatch({type: "SET_TEXT", text: "blue"})
}
const setColor = () => {
dispatch({type: "SET_COLOR", color: "yellow"})
}
const setToggle = () => {
dispatch({type: "SET_GOOD"})
}
return (
<div>
<p>count: {state!.count}</p>
//뒤에!는 null과 undefiend가 오지 않는다는 의미. 값이 무조건 온다
<p>text: {state!.text}</p>
<p>color: {state!.color}</p>
<p>isGood: {state!.isGood ? "true": "false"}</p>
<div>
<button onClick={setCount}>SET_COUNT</button>
<button onClick={setText}>SET_TEXT</button>
<button onClick={setColor}>SET_COLOR</button>
<button onClick={setToggle}>SET_ISGOOD</button>
</div>
</div>
);
};
export default ReducerSampleEdit;
App.tsx
import React from "react";
import ReducerSampleEdit from "./components/ReducerSampleEdit";
import SampleContext from "./context/SampleContext";
function App() {
return (
<div className="App">
<SampleContext>
<ReducerSampleEdit />
</SampleContext>
</div>
);
}
export default App;
todolist 실습하기
context폴더 안에
TodoContext2.tsx
import React, { Dispatch, useContext, useReducer } from 'react';
import { createContext } from 'react';
const initialState = [
{
id: 1,
text: "이력서, 자소서 쓰기",
isDone: false
},
{
id: 2,
text: "이력서, 자소서 쓰기",
isDone: false
},
{
id: 3,
text: "이력서, 자소서 쓰기",
isDone: false
}
]
//상태를 위한 타입
type State = {
id: number,
text: string,
isDone: boolean
}
//액션을 위한 타입
type Action = {type: "ADDTODO"; todo: State}
| {type: "TOGGLETODO"; id: number}
| {type: "DELTODO"; id: number}
//디스패스 위한 타입
type TodoDispatch = Dispatch<Action>
//Context 생성
const TodoStateContext = createContext<State[] | null>(null); //괄호안 null은 초기값
const TodoDispatchContext = createContext<TodoDispatch | null>(null);
//reducer함수
function reducer(state : State[], action: Action): State[]{
switch(action.type){
case "ADDTODO":
return [
...state,
action.todo
];
case "DELTODO":
return state.filter(li=>li.id !== action.id);
case "TOGGLETODO":
return state.map(li=> li.id === action.id ? {
...li, isDone: !li.isDone}: li)
default:
return state;
}
}
/* interface TodoContextProps {
children: React.ReactNode
} */ //인터페이스 안만들고 객체로 바로 넣음(인터페이스로 만들어도됨)
const TodoContext2 = ({children}:{children:React.ReactNode}) => { //children : 타입지정
const [state, dispatch] = useReducer(reducer, initialState)
return (
<TodoStateContext.Provider value={state}>
<TodoDispatchContext.Provider value={dispatch}>
{children}
</TodoDispatchContext.Provider>
</TodoStateContext.Provider>
);
};
export default TodoContext2;
//state와 dispatch를 리턴해주는 훅
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폴더 안에
TodoInput.tsx
import React, { useRef, useState } from 'react';
import { useTodoDispatch } from '../context/TodoContext2';
const TodoInput = () => {
//인풋의 값을 관리할 상태생성
const [text, setText] = useState("")
const dispatch = useTodoDispatch();
//인풋의 값이 변경될때 호출되는 함수
//text값을 인풋의 값으로 업데이트
const onChange = (e:React.ChangeEvent<HTMLInputElement>) => {
const t = e.target.value
setText(t)
}
const ref = useRef<number>(4)
const onAddTodo = () => {
dispatch({type:"ADDTODO", todo:{
id: ref.current,
text: text,
isDone: false
}})
//인풋 초기화
setText("")
//ref.current +1
ref.current++
}
return (
<div>
<input name="text" value={text} onChange={onChange}/>
<button onClick={onAddTodo}>등록</button>
</div>
);
};
export default TodoInput;
components폴더에서
TodoLists2.tsx
import React from 'react';
import { useTodoDispatch, useTodoState } from '../context/TodoContext2';
const TodoLists2 = () => {
const state = useTodoState()//useContext()
const dispatch = useTodoDispatch()
const onDelTodo = (id:number) => {
dispatch({type: "DELTODO", id:id})
}
const onToggleTodo = (id: number) => {
dispatch({type: "TOGGLETODO", id:id})
}
return (
<div>
<ul>
{state.map(todo=><li key={todo.id}
style={{background: todo.isDone ? "yellow" : undefined}}>
<span onClick={()=>{onToggleTodo(todo.id)}}>{todo.text}</span>
<button onClick={()=>{onDelTodo(todo.id)}}>삭제</button></li>)}
</ul>
</div>
);
};
export default TodoLists2;
App.tsx
import React from 'react';
import TodoInput from './components/TodoInput';
import TodoLists2 from './components/TodoLists2';
import TodoContext2 from './context/TodoContext2';
const App = () => {
return (
<div>
<TodoContext2>
<TodoInput/>
<TodoLists2/>
</TodoContext2>
</div>
);
};
export default App;
728x90
반응형
'typescript' 카테고리의 다른 글
[typescript]react-typescript(redux) (0) | 2023.02.24 |
---|---|
[typescript] as & ReturnType (0) | 2023.02.24 |
[typescript] react-typscript(usereducer) (0) | 2023.02.24 |
[typescript]react - typescript(설치, useState) (0) | 2023.02.24 |
[typescript] class 접근제한자, 정적멤버(static), 추상클래스(abstract) (0) | 2023.02.24 |
댓글