[Type Script] Todo 앱 연습: Context API로 타입스크립트 사용하는 리액트 프로젝트의 state 전역 관리하기

summereuna🐥·2023년 8월 22일

TypeScript

목록 보기
5/13

Context API를 계속 배워야 되나 싶지만...🧐 일단 전역으로 관리를 어떻게 하는지 한번 보자구!

todos-context.tsx 파일 생성


📍/src/sotre 에 todos-context.tsx 파일 생성

type Alias 만들어 타입 표기를 재사용할 수 있게 하기

import TodoClass from "../models/todo";

//type Alias 만들어 타입 표기 재사용하기
type TodosContextObj = {
  items: TodoClass[];
  addTodo: (newTodoText: string) => void;
  removeTodo: (id: string) => void;
};

TodosContext 컨텍스트 모양, 컨텍스트 생성

//TodosContext 컨텍스트 모양

//제네릭 타입 안에 이 객체의 타입 설정해 주기
//=> 위의 type Alias로 만든 TodosContextObj 재사용
export const TodosContext = React.createContext<TodosContextObj>({
  //객체 모양
  items: [],
  addTodo: () => {},
  removeTodo: (id: string) => {},
});

컨텍스트 제공해주는 TodosContextProvider 컴포넌트 생성: 상태관리

import React, { useState } from "react";

//...

//컨텍스트 제공해주는 컴포넌트 만들기
//컨텍스트의 상태를 관리하는 역할을 함
type Props = {
  children?: React.ReactNode;
};

const TodosContextProvider: React.FC<Props> = (props) => {
  //상태관리
  const [todos, setTodos] = useState<TodoClass[]>([]);

  //Todo 추가하기
  //newTodoText를 받기 때문에 위에 타입 정의 해줘야 함
  const addTodoHandler = (newTodoText: string) => {
    const newTodo = new TodoClass(newTodoText);
    setTodos((prevTodos) => {
      return prevTodos.concat(newTodo);
    });
  };

  //Todo 삭제하기
  const removeTodoHandler = (clickedTodoId: string) => {
    setTodos((prevTodos) => {
      return prevTodos.filter((todo) => todo.id !== clickedTodoId);
    });
  };

  //Context Value 타입 모양대로 만들기
  const contextValue: TodosContextObj = {
    items: todos,
    addTodo: addTodoHandler,
    removeTodo: removeTodoHandler,
  };

  
  //밸류 값에 타입 모양대로 만든 contextValue 객체 넣어주기
  return (
    <TodosContext.Provider value={contextValue}>
      {props.children}
    </TodosContext.Provider>
  );
};

//Provider는 기본으로 익스포트
export default TodosContextProvider;

📍 App.tsx


App.tsx에서 프로파이더 컴포넌트로 하위 컴포넌트 감싸서 Context 사용할 수 있게 하기

그리고 필요 없는 부분 다 제거하여 코드 정리하기

import "./App.css";
import NewTodo from "./components/NewTodo";
import Todos from "./components/Todos";
import TodosContextProvider from "./store/todos-context";

function App() {
  return (
    <TodosContextProvider>
      <NewTodo />
      <Todos />
    </TodosContextProvider>
  );
}

export default App;

📍 NewTodo.tsx

필요 없는 props 부분과 type 부분 삭제하여 코드 정리하기

useContext() 사용하여 props으로 받던 상태 ctx로 대체하기

import { useRef, useContext } from "react";
import classes from "./NewTodo.module.css";
import { TodosContext } from "../store/todos-context";

//🔥 필요없는 타입 삭제 및 정리
const NewTodo: React.FC = () => {
  //🔥 컨텍스트 추가
  const todosCtx = useContext(TodosContext);

  const todoTextInputRef = useRef<HTMLInputElement>(null);

  const submitHandler = (event: React.FormEvent) => {
    event.preventDefault();
    const enteredText = todoTextInputRef.current!.value;

    if (enteredText.trim().length === 0) {
      return;
    }
    
    todosCtx.addTodo(enteredText); //🔥 props으로 받던거 컨텍스트로 대체
  };

  return (
    <form className={classes.form} onSubmit={submitHandler}>
      <label htmlFor="text">Todo 입력</label>
      <input id="text" name="text" type="text" ref={todoTextInputRef}></input>
      <button type="submit">추가</button>
    </form>
  );
};

export default NewTodo;

📍 Todo.tsx

import React, { useContext } from "react";
import Todo from "./Todo";
import classes from "./Todos.module.css";

import { TodosContext } from "../store/todos-context";

//🔥 필요없는 타입 삭제 및 정리
const Todos: React.FC = () => {
  //🔥 컨텍스트 추가
  const todosCtx = useContext(TodosContext);

   //🔥 props으로 받던거 컨텍스트로 대체
  return (
    <ul className={classes.todos}>
      {todosCtx.items.map((item) => (
        <Todo
          key={item.id}
          text={item.text}
          onRemoveTodo={todosCtx.removeTodo.bind(null, item.id)}
        />
      ))}
    </ul>
  );
};
export default Todos;
profile
Always have hope🍀 & constant passion🔥

0개의 댓글