TypeScript : 투두리스트 만들기 (1단계 - React Props)

728x90
반응형

 

TypeScript : 투두리스트 만들기 (2단계 - Redux Toolkit)

TypeScript : 투두리스트 만들기 (1단계 - React Props) Lv1 React를 이용한 TodoList를 만듭니다. Todo를 Create, Delete, Update(완료/취소) 가 가능해야 합니다. 이때, useState와 Props만을 사용합니다. Keyword props drillin

zerotonine2da.tistory.com

Lv1

  • React를 이용한 TodoList를 만듭니다.
  • Todo를 Create, Delete, Update(완료/취소) 가 가능해야 합니다.
  • 이때, useState와 Props만을 사용합니다.

Keyword

props drilling, state 끌어올리기


 

1. 프로젝트 생성 

: npx create-react-app my-first-ts-app --template typescript

 

2. 코드 작성

 

[App.tsx]

1)  useState를 사용하는 todos의 타입 지정하기

import { useState } from 'react';
import './App.css';
import InputForm from './components/InputForm';
import uuid from 'react-uuid';
import Content from './components/Content';
 

export type Todo = {
    id: string;
    title: string;
    content: string;
    isDone: boolean;
};

function App() {
    const initialState: Todo = {
        id: uuid(),
        title: '제목1',
        content: '내용1',
        isDone: false,
    };

    const [todos, setTodos] = useState<Todo[]>([initialState]);

    return (
        <StDiv>
            <StHeader>
                <p>My Todo List📝</p>
                <p>React</p>
            </StHeader>
            <StMain>
                <InputForm todos={todos} setTodos={setTodos} />
                <Content todos={todos} setTodos={setTodos} isDone={false} />
                <Content todos={todos} setTodos={setTodos} isDone={true} />
            </StMain>
            <footer></footer>
        </StDiv>
    );
}

export default App;

 

1) useState<타입> : Todo[ ] : 배열 안 객체 

2) useState 초기값 : [initialState] : 배열 안 객체 

3)  Todo Type은 다른 컴포넌트에서 사용하도록 export 하기

 

 

[InputForm.tsx]

2) 컴포넌트에서  props로 전달받은 데이터 타입 지정하기

import React, { PropsWithChildren, useState } from 'react';
import uuid from 'react-uuid';
import { Todo } from '../App';

type Props = {
    todos: Todo[];
    setTodos: React.Dispatch<React.SetStateAction<Todo[]>>;
};

function InputForm({ todos, setTodos }: Props) {
    const [title, setTitle] = useState<string>('');
    const [content, setContent] = useState<string>('');
    const inputTitle = (e: React.ChangeEvent<HTMLInputElement>) => {
        setTitle(e.target.value);
    };

    const inputContent = (e: React.ChangeEvent<HTMLInputElement>) => {
        setContent(e.target.value);
    };

    const formSubmit = (e: React.FormEvent<HTMLFormElement>) => {
        e.preventDefault();
        if (title === '' || content === '') {
            alert('제목/내용 모두 입력해야합니다.');
            return;
        }

        const newData = {
            id: uuid(),
            title,
            content,
            isDone: false,
        };

        setTodos([...todos, newData]);
        setTitle('');
        setContent('');
    };
    return (
        <StForm onSubmit={formSubmit}>
            <label>제목</label>
            <input value={title} onChange={inputTitle}></input>
            <label>내용</label>
            <input value={content} onChange={inputContent}></input>
            <button type="submit">추가하기</button>
        </StForm>
    );
}
 
export default InputForm;

1) props로 가져오는 데이터 : {todos, setTodos} : Props=>type Props

2) 이벤트 핸들러 타입 지정하기 

 

▼ 이벤트 핸들러 타입 모를때 찾는 방법  

 

 

TypeScript 오류 : 'IntrinsicAttributes & BaseType & { children?: ReactNode; }' 형식에 선언된 'todos' 속성에서 가져

[App.tsx] export type Todo = { id: string; title: string; content: string; isDone: boolean; }; function App() { const initialState: Todo = { id: uuid(), title: '제목1', content: '내용1', isDone: false, }; //데이터 : 배열 안 객체 const [todos, s

zerotonine2da.tistory.com

 

[Content.tsx]

3) 컴포넌트에서  props로 전달받은 데이터 타입 지정하기

import React from 'react';
import { Todo } from '../App';
import styled from 'styled-components';

type Props = {
    todos: Todo[];
    setTodos: React.Dispatch<React.SetStateAction<Todo[]>>;
    isDone: boolean;
};

function Content({ todos, setTodos, isDone }: Props) {
    return (
        <>
            <StDiv> {isDone ? '✌️Done✌️' : '✍️Working'}</StDiv>
            <StDivLayout>
                {todos
                    .filter((item) => item.isDone === isDone)
                    .map((todo) => {
                        return (
                            <StDivTodo key={todo.id}>
                                <h3>{todo.title}</h3>
                                <p>{todo.content}</p>

                                <StDivBtn>
                                    <DeleteButton
                                        onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
                                            const deleted = todos.filter((item) => {
                                                return todo.id !== item.id;
                                            });
                                            setTodos(deleted);
                                        }}
                                    >
                                        삭제
                                    </DeleteButton>
                                    <StateButton
                                        onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
                                            const stateChange = todos.map((item) => {
                                                if (item.id === todo.id) {
                                                    return { ...item, isDone: !item.isDone };
                                                } else {
                                                    return item;
                                                }
                                            });
                                            setTodos(stateChange);
                                        }}
                                    >
                                        {isDone ? '취소' : '완료'}
                                    </StateButton>
                                </StDivBtn>
                            </StDivTodo>
                        );
                    })}
            </StDivLayout>
        </>
    );
}
 

export default Content;

 

 

반응형