[TypeScript] 타입스크립트와 리액트

Jeris·2023년 6월 10일
0

TypeScript

목록 보기
11/11
post-custom-banner

타입스크립트 리액트 시작하기

npm i @types/node @types/react @types/react-dom @types/jest
// tsconfig.json
{
  "compilerOptions": {
    "target": "ES5",
    "module": "CommonJS",
    "strict": true,
    "allowJS": true,
    "esModuleInterop": true,
    "jsx": "react-jsx"
  },
  "include": ["src"]
}
// index.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
// App.tsx
function App() {
  return <div />;
}

export default App;

상태관리와 Props

// App.tsx
import React, { useReducer, useRef } from "react";
import Editor from "@/components/Editor";
import TodoItem from "@/components/TodoItem";
import { Todo } from "types.ts";

type Action = {
  type: "CREATE";
  payload: Todo;
} | {
  type: "DELETE";
  payload: number;
};

const reducer = (state: Todo[], action: Action) => {
  switch (action.type) {
    case "CREATE":
      return [...state, action.payload];
    case "DELETE":
      return state.filter((todo) => todo.id !== action.payload);
    default:
      return state;
  }
};

export const TodoStateContext = React.createContext<Todo[]>([]);
export const TodoDispatchContext = React.createContext<
    React.Dispatch<Action>
    | undefined
  >(undefined);

function App() {
  const [todos, dispatch] = useReducer(reducer, []);
  const idRef = useRef(0);

  return (
    <TodoStateContext.Provider value={todos}>
      <TodoDispatchContext.Provider value={dispatch}>
        <h1>Todo</h1>
        <Editor idRef={idRef} />
        <div>
          {todos.map((todo) => (
            <TodoItem key={todo.id} todo={todo} />
          ))}
        </div>
      </TodoDispatchContext.Provider>
    </TodoStateContext.Provider>
  );
}

export default App;
// components/Editor.tsx
import React, { useState, useContext, useRef } from "react";
import { TodoDispatchContext } from "../App";

interface Props {
  idRef: React.MutableRefObject<number>;
}

const Editor: React.FC<Props> = ({ idRef }) => {
  const [text, setText] = useState("");
  const dispatch = useContext(TodoDispatchContext);

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

  const onClickButton = () => {
    if (dispatch) {
      dispatch({ type: "CREATE", payload: { id: idRef.current++, content: text } });
      setText("");
    }
  };

  return (
    <div>
      <input value={text} onChange={onChangeInput} />
      <button onClick={onClickButton}>Add</button>
    </div>
  );
};

export default Editor;

// components/Todoitem.tsx
import React, { useContext } from "react";
import { TodoDispatchContext } from "../App";
import { Todo } from "types.ts";

interface Props {
  todo: Todo;
}

const TodoItem: React.FC<Props> = ({ todo }) => { // React.FunctionComponent
  const dispatch = useContext(TodoDispatchContext);

  const onClickDelete = () => {
    if (dispatch) {
      dispatch({ type: "DELETE", payload: todo.id });
    }
  };

  return (
    <div>
      {todo.id}: {todo.content}
      <button onClick={onClickDelete}>Delete</button>
    </div>
  );
};

export default TodoItem;

// components/types.ts
export interface Todo {
  id: number;
  content: string;
}

Context API

// components/Editor.tsx
import React, { useContext } from "react";

export const TodoStateContext = React.createContext<Todo[] | null>(null)
export const TodoDispatcchContext = React.createContext<{
  onClickAdd: (text: string) => void;
  onClickDelete: (id: number) => void;
} | null>(null);

export const useTodoDispatch = () => {
  const dispatch = useContext(TodoDispatchContext);
  if (!dispatch) throw new Error("err");
  return dispatch;
}

//...

	<TodoStateContext.Provider value={todos}>
      <TodoDispatchContext.Provider
        value={{
          onClickAdd,
          onClickDelete,
        }}
      >
        <Editor />
        <div>
          {todos.map(todo) => (
            <TodoItem key={todo.id} {...todo} />
          ))}
        </div
      </TodoDispatchContext.Provider>}>
	</TodoStateContext.Provider>

Reference

profile
job's done
post-custom-banner

0개의 댓글