学習リアクションタイプスクリプト-4(タイプスクリプト環境でリアクションタイプAPIを正しく使用)

24421 ワード

次に、タイプスクリプト環境でContext APIを正しく使用する方法について説明します.Context APIを使用する場合、コード構造を取得するための決定的な方法は存在しません.Contextの準備にクラス構成部品を使用するか、関数構成部品を使用することができます.
Context APIを使用する様々な方法の中から、あなたが便利だと思う方法を見てみましょう.(このポスターはベロフォードさんの反応型シナリオ実習を学ぶものです.)

プロジェクトの準備


まず、Context APIを練習するタイプのスクリプトを適用した反応項目を用意してください.
$ npx create-react-app ts-context-api-tutorial --template typescript
まず、Context APIを使用してダブルリストを作成します.
Context APIを使用する前に、いくつかのコンポーネントを作成します.
作成する構成部品は次のとおりです.

  • TodoForm.tsx:新規保留中の登録に使用

  • TodoItem.tsx:やるべきことを表示する

  • TodoList.tsx:複数のTodoItemをレンダリングする
    srcディレクトリにコンポーネントディレクトリを作成し、各コンポーネントを作成します.
  • src/components/TodoForm.tsx


    TodoForm構成部品は、新しいアイテムを登録できる構成部品です.このコンポーネントでinputとbuttonをレンダリングしてください.Inputの値はuserStateで管理されます.また、submitイベントが発生した場合は、新しいプロジェクトを作成して値を初期化し、後で新しいプロジェクトを作成する部分を実装します.
    import React, { useState } from 'react';
    
    function TodoForm() {
        const [value, setValue] = useState('');
    
        const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
            e.preventDefault();
            // TODO : 새 항목 생성하기
            setValue('');
        };
    
        return (
            <form onSubmit={onSubmit}>
                <input value={value} placeholder="무엇을 하실 건가요?" onChange={e => setValue(e.target.value)} />
                <button>등록</button>
            </form>
        );
    }
    
    export default TodoForm;

    src/components/TodoItem.tsx


    TodoItem構成部品は、作成するアイテムに関する情報を表示する構成部品です.propsはtodoオブジェクトを受信します.場合done値が真の場合、CSSクラスが適用されます.
    import React from 'react';
    import './TodoItem.css';
    
    export type TodoItemProps = {
        todo: {
            id: number;
            text: string;
            done: boolean;
        };
    }
    
    function TodoItem({ todo }: TodoItemProps) {
        return (
            <li className={`TodoItem ${todo.done ? 'done' : ''}`}>
                <span className="text">{todo.text}</span>
                <span className="remove">(X)</span>
            </li>
        );
    }
    
    export default TodoItem;
    上記のコンポーネントのcssファイルも作成してください.

    src/components/TodoItem.css

    .TodoItem .text {
        cursor: pointer;
    }
    
    .TodoItem.done .text {
        color: #999999;
        text-decoration: line-through;
    }
    
    .TodoItem .remove {
        color: red;
        margin-left: 4px;
        cursor: pointer;
    }

    src/components/TodoList.tsx


    次に、最後のコンポーネントTodoListを作成します.この構成部品は、todosという配列を使用して複数のtodoItems構成部品をレンダリングします.このアレイの状態はまだ存在しないため、一時的にTodoList内部でアレイを宣言します.
    import React from 'react';
    import TodoItem from './TodoItem';
    
    function TodoList() {
    
        const todos = [
            {
                id: 1,
                text: 'Context API 배우기',
                done: true
            },
            {
                id: 2,
                text: 'TypeScript 배우기',
                done: true
            },
            {
                id: 3,
                text: 'TypeScript와 Context API 배우기',
                done: false
            }
        ];
    
        return (
            <ul>
                {todos.map(todo => (
                    <TodoItem todo={todo} key={todo.id} />
                ))}
            </ul>
        );
    }
    
    export default TodoList;

    src/App.tsx


    次に、作成した構成部品をAPPでレンダリングします.
    import React from 'react';
    import TodoForm from './components/TodoForm';
    import TodoList from './components/TodoList';
    
    const App = () => {
      return (
        <>
          <TodoForm />
          <TodoList />
        </>
      );
    };
    
    export default App;
    以下の結果が出ましたか?

    Contextの準備


    では今から本格的にContext APIを使いましょうsrcディレクトリにコンテキストディレクトリを作成し、そこにTodosContextを作成します.tsxファイルを作成します.
    私たちはTodosContextですtsxファイルに2つのContextを作成する1つは「ステータスのみ」Context、もう1つは「派遣のみ」Contextです.この2つのContextを作成すると、レンダリング時間の無駄がなくなります.
    ステータスとdispatch関数を1つのコンテキストに配置すると、ステータスを更新するときにステータスは必要なく、dispatch関数のみを必要とする構成部品も再レンダリングされます.2つのContextを作成して管理する場合は、このような状況を回避できます.

    ステータスのみのContextの作成


    まず、状態Contextのみを宣言します.

    src/contexts/TodosContext.tsx

    import { createContext } from 'react';
    
    // 나중에 다른 컴포넌트에서 타입을 불러와서 쓸 수 있도록 내보내겠습니다. (export 키워드로 내보냄)
    export type Todo = {
        id: number;
        text: string;
        done: boolean;
    };
    
    type TodosState = Todo[];
    
    const TodosStateContext = createContext<TodosState | undefined>(undefined);
    Contextを作成する場合は、上記のコードのcreateContext関数のGenericsを使用して、Contextで管理する値の状態を設定できます.後でProviderを使用しない場合、Contextの値は未定義である必要があります.Contextの値は、

    アクションのタイプを宣言


    次に、アクション映画のタイプを宣言します.私たちは全部で3種類のアクション映画を作ります.
  • CREATE:新規プロジェクト作成
  • TOGLE:done値反転
  • REMOVE:削除項目
  • src/contexts/TodosContext.tsx

    import { createContext } from 'react';
    
    // 나중에 다른 컴포넌트에서 타입을 불러와서 쓸 수 있도록 내보내겠습니다. (export 키워드로 내보냄)
    export type Todo = {
        id: number;
        text: string;
        done: boolean;
    };
    
    type TodosState = Todo[];
    
    const TodosStateContext = createContext<TodosState | undefined>(undefined);
    
    type Action =
        | { type: 'CREATE'; text: string }
        | { type: 'TOGGLE'; id: number }
        | { type: 'REMOVE'; id: number };
    これにより、アクションタイプを宣言した後、dispatchのContextを作成し、dispatch関数のタイプを設定できます.

    contexts/TodosContest.tsx

    import { createContext, Dispatch } from 'react';
    
    // 나중에 다른 컴포넌트에서 타입을 불러와서 쓸 수 있도록 내보내겠습니다. (export 키워드로 내보냄)
    export type Todo = {
        id: number;
        text: string;
        done: boolean;
    };
    
    type TodosState = Todo[];
    
    const TodosStateContext = createContext<TodosState | undefined>(undefined);
    
    type Action =
        | { type: 'CREATE'; text: string }
        | { type: 'TOGGLE'; id: number }
        | { type: 'REMOVE'; id: number };
    
    type TodosDispatch = Dispatch<Action>;
    const TodosDispatchContext = createContext<TodosDispatch | undefined>(undefined);
    Dispatchをリアクションパッケージからロードし、動作タイプをGenericに入れることで、後続のコンポーネントで動作を派遣するときに動作タイプをチェックできます.たとえば、text、idなどの他の必要な値が動作中に欠けている場合、エラーが発生します.

    Reduserの作成


    今、やるべきことの管理のためにReduserを作成しましょう.
    import { createContext, Dispatch } from 'react';
    
    // 나중에 다른 컴포넌트에서 타입을 불러와서 쓸 수 있도록 내보내겠습니다. (export 키워드로 내보냄)
    export type Todo = {
        id: number;
        text: string;
        done: boolean;
    };
    
    type TodosState = Todo[];
    
    const TodosStateContext = createContext<TodosState | undefined>(undefined);
    
    type Action =
        | { type: 'CREATE'; text: string }
        | { type: 'TOGGLE'; id: number }
        | { type: 'REMOVE'; id: number };
    
    type TodosDispatch = Dispatch<Action>;
    const TodosDispatchContext = createContext<TodosDispatch | undefined>(undefined);
    
    function todosReducer(state: TodosState, action: Action): TodosState {
        switch (action.type) {
            case 'CREATE':
                const nextId = Math.max(...state.map(todo => todo.id)) + 1;
                return state.concat({
                    id: nextId,
                    text: action.text,
                    done: false
                });
            case 'TOGGLE':
                return state.map(todo =>
                    todo.id === action.id ? { ...todo, done: !todo.done } : todo
                );
            case 'REMOVE':
                return state.filter(todo => todo.id !== action.id);
            default:
                throw new Error('Unhandled Action');
        }
    }
    このタイプのスクリプトを使用してリダイレクトを記述すると、動作のtype値が自動的に完了します.
    アクションのタイプに応じて、アクションオブジェクトの構造がどのように構成されているかをIDEで直接確認できます.

    TodosProviderの作成


    ここでは、TodosStateContextというプロバイダが、TodosDispatchContextのプロバイダとともに使用されるコンポーネントを用意します.
    import React, { createContext, Dispatch, useReducer } from 'react';
    
    (...) // (이전 코드 생략)
    
    export function TodosContextProvider({ children }: { children: React.ReactNode }) {
        const [todos, dispatch] = useReducer(todosReducer, [
            {
                id: 1,
                text: 'Context API 배우기',
                done: true
            },
            {
                id: 2,
                text: 'TypeScript 배우기',
                done: true
            },
            {
                id: 3,
                text: 'TypeScript 와 Context API 함께 사용하기',
                done: false
            }
        ]);
    
        return (
            <TodosDispatchContext.Provider value={dispatch}>
                <TodosStateContext.Provider value={todos}>
                    {children}
                </TodosStateContext.Provider>
            </TodosDispatchContext.Provider>
        );
    }
    作成したばかりのコンポーネントは、後でアプリケーションから既存のコンテンツをロードしてカプセル化する必要があるため、エクスポートする必要があります.
    Contextはもう準備ができています

    2つのカスタムジョブの作成


    以降、TodosStatecContextとTodosDispatchContextを使用する場合は、以下のように、UserContextを使用してContextの値を使用できます.
    const todos = useContext(TodosStateContext);
    ただし、このときtodosのタイプはTodoState|Undefindである可能性があります.したがって、配列を使用する前に、値が有効であることを確認する必要があります.
    const todos = useContext(TodosStateContext);
    if (!todo) return null;
    そうしても大丈夫だけど…より良い方法は、TodosContextのみのHooksを作成して、より便利に使用することです.次のコードを作成すると、後続のステータスまたはディスパッチをより簡単に使用できます.また、コンポーネントで使用するときに検証をスキップすることもできます.
    カスタムマニュアルを書きましょう.

    src/contexts/TodosContext.tsx

    (...) // 기존 코드 생략
    
    export function useTodosState() {
      const state = useContext(TodosStateContext);
      if (!state) throw new Error('TodosProvider not found');
      return state;
    }
    
    export function useTodosDispatch() {
      const dispatch = useContext(TodosDispatchContext);
      if (!dispatch) throw new Error('TodosProvider not found');
      return dispatch;
    }
    関数に必要な値が無効な場合は、エラーを投げ出すことで、各Hookが返す値のタイプが常に有効であることを確認できます.(無効な場合、エラーはブラウザのコンソールにすぐに表示されます).
    やっとContextが書き終わりましたuseTodosStateとuseTodosDispatchは、他の構成部品の読み込みと使用のためにエクスポートする必要があります.(exportキーワードとして)

    構成部品でのContextの使用


    私たちが作成したContextを使用する必要があります.

    TodosContextProviderによる保護


    まず、既存のコンテンツを上書きするために、アプリケーションコンポーネントからTodosContextProviderを読み込みます.

    src/App.tsx

    import React from 'react';
    import TodoForm from './components/TodoForm';
    import TodoList from './components/TodoList';
    import { TodosContextProvider } from './contexts/TodosContext';
    
    const App = () => {
      return (
        <TodosContextProvider>
          <TodoForm />
          <TodoList />
        </TodosContextProvider>
      );
    };
    
    export default App;

    TooListでステータスを表示する


    次に、ContextにおけるTodoListコンポーネントの状態を確認して、コンテンツのレンダリングを試みます.Custom Hookを作成したので、本当に簡単に処理できます.

    src/components/TodoList.tsx

    import React from 'react';
    import TodoItem from './TodoItem';
    import { useTodosState } from '../contexts/TodosContext';
    
    function TodoList() {
    
        const todos = useTodosState();
    
        return (
            <ul>
                {todos.map(todo => (
                    <TodoItem todo={todo} key={todo.id} />
                ))}
            </ul>
        );
    }
    
    export default TodoList;
    現在のステータスを表示するには、usertoosStateをロードして呼び出すだけです.

    TooFormに新規アイテムを登録する


    では、TooFormに新しいプロジェクトを登録してみましょう.useTodosDispatch Hookでdispatch関数を受信し、dispatch動作を試みます.

    src/components/TodoForm.tsx

    import React, { useState } from 'react';
    import { useTodosDispatch } from '../contexts/TodosContext';
    
    function TodoForm() {
        const [value, setValue] = useState('');
        const dispatch = useTodosDispatch();
    
        const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
            e.preventDefault();
            dispatch({
                type: 'CREATE',
                text: value
            });
            setValue('');
        };
    
        return (
            <form onSubmit={onSubmit}>
                <input value={value} placeholder="무엇을 하실 건가요?" onChange={e => setValue(e.target.value)} />
                <button>등록</button>
            </form>
        );
    }
    
    export default TodoForm;
    コードを記述してアクションをデバッグする場合、アクションタイプが自動的に完了し、アクションに必要な値が欠けている場合、タイプチェックにエラーが表示されます.

    コードを作成した場合は、新しいプロジェクトを入力して登録し、正常に登録できるようにします.

    TooItemでのアイテムの切り替えと削除


    今回は、TodoItemの項目をクリックしたときにdone値を切り替え、右側の(X)をクリックしたときに削除してみます.Contextを使用しない環境では、onToggleおよびonRemove propsをTodoItemコンポーネントからインポートし、呼び出しとして実装する必要がある場合があります.しかし,現在のようにContextを使用すると,これらの関数をpropsでインポートする必要はなく,これらの素子内部から直接動作を派遣するのもよい方法である.

    src/components/TodoItem.tsx

    import React from 'react';
    import './TodoItem.css';
    import { useTodosDispatch, Todo } from '../contexts/TodosContext';
    
    export type TodoItemProps = {
        todo: Todo; // TodoContext에서 선언했던 타입을 불러왔습니다.
    }
    
    function TodoItem({ todo }: TodoItemProps) {
        const dispatch = useTodosDispatch();
    
        const onToggle = () => {
            dispatch({
                type: 'TOGGLE',
                id: todo.id
            });
        };
    
        const onRemove = () => {
            dispatch({
                type: 'REMOVE',
                id: todo.id
            })
        };
        return (
            <li className={`TodoItem ${todo.done ? 'done' : ''}`}>
                <span className="text" onClick={onToggle}>{todo.text}</span>
                <span className="remove" onClick={onRemove}>(X)</span>
            </li>
        );
    }
    
    export default TodoItem;

    これでTodoItemのすべての実装が完了しました!ブラウザでTooItemのアイテムのdoneステータスを切り替えるか、アイテムを削除できます.

    整理する


    今回の学習では,タイプスクリプト環境で反応のContext APIを効率的に利用する方法について理解した.Context APIを使用してステータスを管理する場合は、UserReducerを使用して、ステータスのみのContextと派遣関数のみのContextを作成すると便利です.また、Contextを作成すると、使いやすいカスタムホームページを作成でき、開発が容易になります.
    Velopertの元の位置決めリンク