zoaseo
To Infinity And Beyond
zoaseo
전체 방문자
오늘
어제
  • 분류 전체보기 (763)
    • 개발이 좋아서 (381)
      • SAP가 좋아서 (3)
      • Java가 좋아서 (42)
      • Spring이 좋아서 (50)
      • JPA가 좋아서 (0)
      • QueryDSL이 좋아서 (26)
      • Docker가 좋아서 (7)
      • Redis가 좋아서 (7)
      • AWS가 좋아서 (5)
      • CI/CD가 좋아서 (6)
      • Troubleshooting이 좋아서 (4)
      • Kotlin이 좋아서 (7)
      • SQL이 좋아서 (6)
      • HTTP가 좋아서 (21)
      • JavaScript가 좋아서 (30)
      • TypeScript가 좋아서 (6)
      • Vue가 좋아서 (21)
      • Flutter가 좋아서 (61)
      • React가 좋아서 (20)
      • Redux(React)가 좋아서 (2)
      • Angular가 좋아서 (22)
      • HTML이 좋아서 (9)
      • CSS가 좋아서 (15)
      • PHP가 좋아서 (9)
      • Illustrator가 좋아서 (2)
    • 노력이 좋아서 (169)
    • 결과물이 좋아서 (14)
    • 코딩연습이 좋아서 (168)
      • 이론이 좋아서 (62)
      • SQL이 좋아서 (90)
    • 유용한 사이트가 좋아서 (28)
    • Github (2)

인기 글

티스토리

hELLO · Designed By 정상우.
zoaseo
노력이 좋아서

<step90>'react_ts_todoList_useContext'

노력이 좋아서

<step90>'react_ts_todoList_useContext'

2022. 7. 28. 10:29

1)

todoContext.tsx

import React, { createContext, Dispatch, ReactNode, useReducer, useContext } from 'react';
import InsertTodo from './components/InsertTodo';
import TodoList from './components/TodoList';

// 상태관리할 데이터
// 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':
            return {
                ...state,
                inputText: action.inputText
            }
        case 'CREATE_TODO':
            return {
                ...state,
                todos: [
                    ...state.todos,
                    action.todo
                ],
                inputText: ""
            }
        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: 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를 쉽게 사용하기 위한 커스텀 hook
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;
}

App.tsx

import React, { useReducer } from 'react';
import InsertTodo from './components/InsertTodo';
import TodoList from './components/TodoList';
import { TodoContext, useTodoDispatch, useTodoState } from './todoContext';

// 상태관리할 데이터
// 1.input의 값
// 2.할일목록
export type Todo = {
    id: number;
    text: string;
    isDone: boolean;
}

const App = () => {
    const state = useTodoState();
    const dispatch = useTodoDispatch();

    const { inputText, todos } = state;
    const onChange = (text:string) => dispatch({type: 'INPUT_CHANGE', inputText:text})
    const onCreate = () => dispatch({type: 'CREATE_TODO', todo: {
        id:3,
        text: state.inputText,
        isDone: false
    }})
    const onDelete = (id:number) => dispatch({type: 'DELETE_TODO', id:id})
    return (
        <TodoContext>
            <div>
                <InsertTodo inputText={inputText} onChange={onChange} onCreate={onCreate}/>
                <TodoList todos={todos} onDelete={onDelete}/>
            </div>
        </TodoContext>
    );
};

export default App;

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;

TodoList.tsx

import React from 'react';
// import { Todo } from '../App3';
import { Todo } from '../todoContext';

type TodoProps = {
    todos: Todo[];
    onDelete(id:number): void
}
const TodoList = ({todos, onDelete} : TodoProps) => {
    return (
        <div>
            <ul>
                {todos.map(todo=><li key={todo.id}><span>{todo.text}</span><button onClick={()=>onDelete(todo.id)}>삭제</button></li>)}
            </ul>
        </div>
    );
};

export default TodoList;

index.tsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { TodoContext } from './todoContext';

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  <React.StrictMode>
    <TodoContext>
    <App/>
    </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();

'노력이 좋아서' 카테고리의 다른 글

<step91>'react(redux)_ts_todoList'  (0) 2022.07.29
<step90>'react(redux)_ts_counter'  (0) 2022.07.28
<step90>'react_ts_SampleContext'  (0) 2022.07.28
<step89>'react_ts_todoList'  (0) 2022.07.27
<step89>'react_ts_userList'  (0) 2022.07.27

    티스토리툴바

    단축키

    내 블로그

    내 블로그 - 관리자 홈 전환
    Q
    Q
    새 글 쓰기
    W
    W

    블로그 게시글

    글 수정 (권한 있는 경우)
    E
    E
    댓글 영역으로 이동
    C
    C

    모든 영역

    이 페이지의 URL 복사
    S
    S
    맨 위로 이동
    T
    T
    티스토리 홈 이동
    H
    H
    단축키 안내
    Shift + /
    ⇧ + /

    * 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.