방명록
- [TypeScript] React.js에서 타입스크립트 사용(udemy 강의 "Typescript :기초부터 실전형 프로젝트까지 with React + NodeJS" 섹션 14)2024년 03월 06일 11시 09분 33초에 업로드 된 글입니다.작성자: DandyNow728x90반응형
섹션 14: React.js 및 TypeScript
📌 React.js + TypeScript 프로젝트 생성
.은 현재 경로에 프로젝트를 생성하는 것을 말한다.
npx create-react-app . --template typescript
😉 공식 문서 : https://create-react-app.dev/docs/adding-typescript/
📌 React.FC
// src/app.tsx import React from "react"; // React.FC는 리액트 함수 컴포넌트 사용함을 의미 const App: React.FC = () => { return <div className="App"></div>; } export default App;
📌 React.FC와 <>
React.FC에 화살 괄호 <>를 사용해 props의 타입을 지정할 수 있다. 여기에서는 TodoListProps 인터페이스를 생성하여 타입을 지정했다.
// src/components/TodoList.tsx import React from "react"; // 인터페이스로 prop로 받을 items 객체 타입 정의 interface TodoListProps { items: { id: string; text: string }[]; } const TodoList: React.FC<TodoListProps> = (props) => { // React.FC 화살괄호 안에 TodoListProps 인터페이스 추가 return ( <ul> {props.items.map((todo) => ( <li key={todo.id}>{todo.text}</li> ))} </ul> ); }; export default TodoList;
더보기// src/app.tsx import React from "react"; import TodoList from "./components/TodoList"; const App: React.FC = () => { const todos = [{ id: "t1", text: "Finish the course" }]; return ( <div className="App"> <TodoList items={todos} /> </div> ); }; export default App;
📌 React.FormEvent, HTMLInputElement
input 창에 텍스트를 입력하고 "ADD TODO" 버튼을 누르면 콘솔에 해당 텍스트가 찍히는 코드이다. input event의 타입은 React.FormEvent이다. useRef의 타입은 HTMLInputElement이다.
// src/components/NewTodo.tsx import React, { useRef } from "react"; const NewTodo: React.FC = () => { const textInputRef = useRef<HTMLInputElement>(null); const todoSubmitHandler = (event: React.FormEvent) => { event.preventDefault(); const enteredText = textInputRef.current!.value; console.log(enteredText); }; return ( <form onSubmit={todoSubmitHandler}> <div> <label htmlFor="todo-text">Todo Text</label> <input type="text" id="todo-text" ref={textInputRef} /> </div> <button type="submit">ADD TODO</button> </form> ); }; export default NewTodo;
더보기// src/app.tsx import React from "react"; import TodoList from "./components/TodoList"; import NewTodo from "./components/NewTodo"; const App: React.FC = () => { const todos = [{ id: "t1", text: "Finish the course" }]; return ( <div className="App"> <TodoList items={todos} /> {/* NewTodo 컴포넌트 추가 */} <NewTodo /> </div> ); }; export default App;
📌 type alias와 함수 타입
props로 함수를 넘겨 자식 컴포넌트에서 input으로 입력된 텍스트 값을 부모 컴포넌트에서 이용하고자 한다. 이때 props로 넘긴 함수의 타입을 정의해 주어야 한다.
// src/components/NewTodo.tsx import React, { useRef } from "react"; // type alias를 이용해 onAddTodo() 함수의 타입을 정의 type NewTodoProps = { onAddTodo: (todoText: string) => void; }; const NewTodo: React.FC<NewTodoProps> = (props) => { // React.FC의 <>에 정의한 타입 지정 const textInputRef = useRef<HTMLInputElement>(null); const todoSubmitHandler = (event: React.FormEvent) => { event.preventDefault(); const enteredText = textInputRef.current!.value; props.onAddTodo(enteredText); // enteredText 값을 onAddTodo() 함수를 이용해 부모 컴포넌트로 넘김 }; return ( <form onSubmit={todoSubmitHandler}> <div> <label htmlFor="todo-text">Todo Text</label> <input type="text" id="todo-text" ref={textInputRef} /> </div> <button type="submit">ADD TODO</button> </form> ); }; export default NewTodo;
더보기// src/App.tsx import React from "react"; import TodoList from "./components/TodoList"; import NewTodo from "./components/NewTodo"; const App: React.FC = () => { const todos = [{ id: "t1", text: "Finish the course" }]; // props로 넘길 함수 정의 const todoAddHandler = (text: string) => { console.log(text); }; return ( <div className="App"> {/* NewTodo 컴포넌트 props로 todoAddHandler() 함수 넘김 */} <NewTodo onAddTodo={todoAddHandler} /> <TodoList items={todos} /> </div> ); }; export default App;
📌 useState의 경우
// src/App.tsx import React, { useState } from "react"; import TodoList from "./components/TodoList"; import NewTodo from "./components/NewTodo"; import { Todo } from "./todo.model"; // 타입 정의 추가 const App: React.FC = () => { // const [todos, setTodos] = useState<{id: string; text: string}[]>([]); // props로 받는 객체 타입을 직접 정의한 경우 const [todos, setTodos] = useState<Todo[]>([]); // props로 받는 객체 타입을 todo.model.ts 파일에 정의한 경우 // 기존 상태값 업데이트 const todoAddHandler = (text: string) => { setTodos((prevTodos) => [ ...prevTodos, { id: Math.random().toString(), text: text }, ]); }; return ( <div className="App"> <NewTodo onAddTodo={todoAddHandler} /> <TodoList items={todos} /> </div> ); }; export default App;
// src/todo.model.ts export interface Todo { id: string; text: string; }
📌 todo 삭제와 bind
버튼의 클릭 이벤트로 함수를 호출할 때 bind나 화살 괄호를 사용하지 않으면 에러가 발생한다. 에러의 내용은 다음과 같다.
Type 'void' is not assignable to type 'MouseEventHandler<HTMLButtonElement> | undefined'.
ts(2322)
index.d.ts(2427, 9): The expected type comes from property 'onClick' which is declared here on type 'DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>'아래 코드에는 button 태그의 onClick 속송에 bind와 화살 괄호를 각각 사용해본 코드가 포함되어 있다.
// src/componets/TodoList.tsx import React from "react"; interface TodoListProps { items: { id: string; text: string }[]; onDeleteTodo: (id: string) => void; // 타입 추가 } const TodoList: React.FC<TodoListProps> = (props) => { return ( <ul> {props.items.map((todo) => ( <li key={todo.id}> <span>{todo.text}</span> {/* bind 사용한 경우 */} <button onClick={props.onDeleteTodo.bind(null, todo.id)}> DELETE(bind) </button> {/* 화살표 함수 사용한 경우 */} <button onClick={() => props.onDeleteTodo(todo.id)}>DELETE</button> </li> ))} </ul> ); }; export default TodoList;
// src/App.tsx import React, { useState } from "react"; import TodoList from "./components/TodoList"; import NewTodo from "./components/NewTodo"; import { Todo } from "./todo.model"; const App: React.FC = () => { const [todos, setTodos] = useState<Todo[]>([]); const todoAddHandler = (text: string) => { setTodos((prevTodos) => [ ...prevTodos, { id: Math.random().toString(), text: text }, ]); }; // todo 삭제를 당담하는 함수 const todoDeleteHandler = (todoId: string) => { setTodos((prevTodos) => { return prevTodos.filter((todo) => todo.id !== todoId); }); }; return ( <div className="App"> <NewTodo onAddTodo={todoAddHandler} /> {/* todoDeleteHandler 함수를 props로 보냄 */} <TodoList items={todos} onDeleteTodo={todoDeleteHandler} /> </div> ); }; export default App;
📌 스타일 추가
스타일을 import하는 방식에 유의!
// src/components/TodoList.tsx import React from "react"; import "./TodoList.css"; // 추가 // (생략)
// src/components/NewTodo import React, { useRef } from "react"; import "./NewTodo.css"; // 추가 // (타입 정의 생략) const NewTodo: React.FC<NewTodoProps> = (props) => { // (생략) return ( <form onSubmit={todoSubmitHandler}> {/* className 속성 추가 */} <div className="form-control"> <label htmlFor="todo-text">Todo Text</label> <input type="text" id="todo-text" ref={textInputRef} /> </div> <button type="submit">ADD TODO</button> </form> ); }; export default NewTodo;
더보기/* src/components/TodoList.css */ ul { list-style: none; width: 90%; max-width: 40rem; margin: 2rem auto; padding: 0; } li { margin: 1rem 0; padding: 1rem; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.26); border-radius: 6px; display: flex; justify-content: space-between; align-items: center; }
/* src/components/NewTodo.css */ form { width: 90%; max-width: 40rem; margin: 2rem auto; } .form-control { margin-bottom: 1rem; } label, input { display: block; width: 100%; } label { font-weight: bold; } input { font: inherit; border: 1px solid #ccc; padding: 0.25rem; } input:focus { outline: none; border-color: #50005a; } button { background: #50005a; border: 1px solid #50005a; color: white; padding: 0.5rem 1.5rem; cursor: pointer; } button:focus { outline: none; } button:hover, button:active { background: #6a0a77; border-color: #6a0a77; }
728x90반응형'언어·프레임워크 > TypeScript' 카테고리의 다른 글
다음글이 없습니다.이전글이 없습니다.댓글