본문 바로가기

온라인 강의(유데미, 인프런 등)/React 완벽 가이드(유데미)

[typescript] typescript 개념 정리(2)

반응형

React with TypeScript

  • 설치 
npx create-react-app 프로젝트 이름 --template typescript
  • 리액트는 jsx문법을 사용하기 때문에 typescript를 사용할 때 확장자명을 ts가 아닌 tsx로 사용한다(컴포넌트를 생성하는 게 아니라면 ts로 작성해도 됨).

 

props의 타입 지정 : React.FC

  • props의 타입을 Generics로 지정한다. -> FC 자체가 Generics 타입이다.
  • React.FC를 사용하면 props에 기본적으로 children 이 들어가 있고, 컴포넌트의 defaultProps, propTypes, contextTypes를 설정할 때 자동완성 기능을 이용할 수 있다.
  • React.FC가 이미 제네릭 타입이기 때문에 타입은 이미 정의된 것이다.
  • <{}>은 제네릭 타입을 만드는 구문이다. 안에 필요한 props의 타입을 지정한다.이를 통해 이 컴포넌트를 위해 만든 props와 children 같은 기본적인 props가 합쳐진다.
// React.FC 사용
const Todos: React.FC<{ items: Todo[]; onRemoveTodo: () => void }> = props => {
  return (
    <ul>
      {props.items.map(item => (
        <li key={item}>{item}</li>
      ))}
    </ul>
  );
};

// React.FC 사용 x
const Todos = (props: { items: string[], children: ...}) => {
  return (
    <ul>
      {props.items.map(item => (
        <li key={item}>{item}</li>
      ))}
    </ul>
  );
};

 

데이터 모델 추가

컴포넌트나 데이터를 잘못 이용할 경우를 방지해 준다.

export interface Todo {
    id: string;
    text: string;
}

const Todos: React.FC<{ items: Todo[] }> = props => {
  return (
    <ul>
      {props.items.map(item => (
        <li key={item}>{item}</li>
      ))}
    </ul>
  );
};

 

typescript의 양식 제출

// form submit event type
event: React.FormEvent

// onClick event type
event: React.MouseEvent

 

typescript의 ref와 useRef

  • 이 ref가 입력창에 연결될 거라는 것을 명시해야 한다. -> 제네릭 타입으로 정의해야 한다.
  • useRef 자체가 제네릭 타입으로 되어있다.
  • button이라면 HTMLButtonElement, paragraph라면 HTMLParagraphElement을 사용한다.
  • 시작값을 null로 지정해야 한다.

# 연산자 !

  • 뒤에 느낌표를 붙이면 앞의 값이 확실히 null이나 undefined가 아니라는 걸 알린다.
  • null 일 수 없다고 100% 확신하는 경우에만 사용한다.

# 연산자 ?

  • null 일 경우, 상수 또는 값을 저장할 곳에 null을 저장한다.
const todoTextInputRef = useRef<HTMLInputElement>(null);

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

return(
	...
    <form onSubmit={submitHandler}
		<input type="text" id="text" ref={todoTextInputRef}>
        ...
    </form>
)

 

함수 props 타입 지정

const NewTodo: React.FC<{onAddTodo: (text: string) => void}> = props => { 
...

 

state 타입 지정

// setTodos의 타입 => dispatch
// useState의 타입 => 제네릭
const [todos, setTodos] = useState<Todo[]>([]);

 

# bind

실행할 함수를 미리 설정할 수 있는 메서드

// 첫번째 아규먼트: this가 무엇을 가르키는지 설정
// 두번째 아규먼트: 함수가 매개변수로 받는 값 설정
onRemoveTodo = {props.onRemoveTodo.bind(null, item.id)}

 

Context API

// store/todos-context.tsx
import React, { useState } from 'react';

import Todo from '../models/todo';

type TodosContextObj = {
  items: Todo[];
  addTodo: (text: string) => void;
  removeTodo: (id: string) => void;
};

// createContext => 제네릭 타입
export const TodosContext = React.createContext<TodosContextObj>({
  items: [],
  addTodo: () => {},
  removeTodo: (id: string) => {},
});

const TodosContextProvider: React.FC = (props) => {
  const [todos, setTodos] = useState<Todo[]>([]);

  const addTodoHandler = (todoText: string) => {
    const newTodo = new Todo(todoText);

    setTodos((prevTodos) => {
      return prevTodos.concat(newTodo);
    });
  };

  const removeTodoHandler = (todoId: string) => {
    setTodos((prevTodos) => {
      return prevTodos.filter((todo) => todo.id !== todoId);
    });
  };

  const contextValue: TodosContextObj = {
    items: todos,
    addTodo: addTodoHandler,
    removeTodo: removeTodoHandler,
  };

  return (
    <TodosContext.Provider value={contextValue}>
      {props.children}
    </TodosContext.Provider>
  );
};

export default TodosContextProvider;

// Todos.tsx

import { userContext } from 'react';
import { TodosContext } from '../store/todos-context';

const todosCtx = useContext(TodosContext);

// App.tsx

import TodosContextProvider from './store/todos-context';

return(
	<TodosContextProvider>
    	<NewTodo />
        <Todos />
    </TodosContextProvider>
)
반응형