学習反応型スクリプト-3(反応型コードを使用)

32731 ワード

前回のレッスンでは、タイプスクリプトを適用したレスポンスプロジェクトの作成方法と、タイプスクリプトを使用してコンポーネントを作成する方法について学習しました.
ここでは、タイプスクリプトを使用したレスポンス構成部品で「ユーザーステータス」と「ユーザーモニタ」を使用して構成部品のステータスを管理する方法と、「ユーザーRef」を使用して構成部品内で変数とDOMを管理する方法について学習します.

useStateとイベントの管理


タイプスクリプト環境でusStateを使用する方法と、イベントをどのように処理するかを学習します.

カウンタの作成


まず、これは非常に簡単な例です.多くのカウンタを作成した可能性があります.UserState Hookを使用して実現します.
srcディレクトリで偶数です.tsxファイルを生成したら、次のようにコードを記述します.

Counter.tsx

import React, { useState } from 'react';

function Counter() {
    const [count, setCount] = useState<number>(0);
    const onIncrease = () => setCount(count + 1);
    const onDecrease = () => setCount(count - 1);
    return (
        <div>
            <h1>{count}</h1>
            <div>
                <button onClick={onIncrease}>+1</button>
                <button onClick={onDecrease}>+1</button>
            </div>
        </div>
    );
}

export default Counter;
タイプスクリプトを使用せずにレスポンス構成部品を作成できます.userStateを使用する場合は、userState()などのタイプをGenericsで設定するだけです.
アプリでこのコンポーネントをレンダリングして、正常に動作しているかどうかを確認しましょう.
src/App.tsx
import React from 'react';
import Counter from './Counter';

function App() {
  return <Counter />;
};

export default App;

よく動いていますただし、useStateを使用する場合はGenericsを使用する必要はありません.必要に応じてタイプを選択できるので、省略できます.

src/Counter.tsx

import React, { useState } from 'react';

function Counter() {
    const [count, setCount] = useState(0);
    const onIncrease = () => setCount(count + 1);
    const onDecrease = () => setCount(count - 1);
    return (
        <div>
            <h1>{count}</h1>
            <div>
                <button onClick={onIncrease}>+1</button>
                <button onClick={onDecrease}>+1</button>
            </div>
        </div>
    );
}

export default Counter;

だから実際にやらなくても大丈夫…!では、userStateを使用する場合、どのような場合にGenericsを使用すればよいのでしょうか.
ステータスが空であっても空でなくてもよい場合はGenericsを使用します.
type Information = { name: string; description: string; };
const [info, setInformation] = useState<Information | null>(null);
また、オブジェクトのタイプが複雑な構造のオブジェクト、または配列の場合は、Genericsを指定することをお勧めします.
type Todo = { id: number; text: string; done: boolean };
const [todos, setTodos] = useState<Todo[]>([]);
タイルの場合はGenericsを指定する必要があります.前述の空のタイルだけでは、タイルがどのタイプで構成されているかは推定できません.Genericsを使用しない場合は、次のことができます.
type Todo = { id: number; text: string; done: boolean };
const [todos, setTodos] = useState([] as Todo[]);
ここで使用するasは、特定の値が特定のタイプの情報を上書きできるType Assertionという構文です.
  • リンク:https://www.typescriptlang.org/docs/handbook/basic-types.html#type-assertions2
  • 入力ステータスの管理


    今回はInputの状態を管理する方法を学びますイベントを処理するため、指定したタイプは最初はどうすればいいか混同される可能性がありますが、どうすればいいかが分かったら簡単です.
    MyFormという名前のコンポーネントを作成します.

    src/MyForm.tsx

    import React, { useState } from 'react';
    
    type MyFormProps = {
       onSubmit: (form: { name: string; description: string }) => void;
    };
    
    function Myform({ onSubmit }: MyFormProps) {
       const [form, setForm] = useState({ name: '', description: '' });
    
       const { name, description } = form;
    
       const onChange = (e: any) => {
           // e 값을 무엇으로 설정해야할까?
           // 일단 모를 때는 any로 설정한다.
       };
    
       const handleSubmit = (e: any) => {
           // 여기도 모르니 any 로 하겠습니다.
       };
    
       return (
           <form onSubmit={handleSubmit}>
               <input name="name" value={name} onChange={onChange} />
               <input name="description" value={description} onChange={onChange} />
               <button type="submit">등록</button>
           </form>
       );
    }
    
    export default Myform;
    タイプスクリプトを最初に作成した人であれば、eオブジェクトのタイプを知らない可能性があります.ただし、Googleで「Type Script react onChange event」を検索する必要はありません.eオブジェクトのタイプを覚える必要はありません.onChangeにカーソルを置きましょう

    カーソルが止まると、どのタイプを使用するべきかが表示されます.そのままマウスでドラッグしてコピーすればいいです.(マウスカーソルを移動するときは、外に移動しないように注意してください.)
    では、onChangeでeオブジェクトのタイプを変更します.ChangeEventとして指定して実装します.onSubmitも同様で、カーソルが止まるとReactが表示されます.FormEventをeオブジェクトのタイプとして指定し、実装を試みます.

    src/MyForm.tsx

    import React, { useState } from 'react';
    
    type MyFormProps = {
        onSubmit: (form: { name: string; description: string }) => void;
    };
    
    function Myform({ onSubmit }: MyFormProps) {
        const [form, setForm] = useState({ name: '', description: '' });
    
        const { name, description } = form;
    
        const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
            const { name, value } = e.target;
            setForm({
                ...form,
                [name]: value
            });
        };
    
        const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
            e.preventDefault();
            onSubmit(form);
            setForm({
                name: '',
                description: ''
            }); //  초기화
        };
    
        return (
            <form onSubmit={handleSubmit}>
                <input name="name" value={name} onChange={onChange} />
                <input name="description" value={description} onChange={onChange} />
                <button type="submit">등록</button>
            </form>
        );
    }
    
    export default Myform;
    では、アプリでレンダリングして、正常に動作しているかどうかを見てみましょう.
    src/App.tsx
    import React from 'react';
    import MyForm from './MyForm';
    
    function App() {
    const onSubmit = (form: { name: string; description: string }) => {
      console.log(form);
    };
    return <MyForm onSubmit={onSubmit} />;
    };
    
    export default App;

    仕事がうまい!

    useReducer


    先ほど作成したカウンタ構成部品を、usStateではなくuserDeducerを使用するコードに変換しましょう.
    src/Counter.tsx
    import React, { useReducer } from 'react';
    
    type Action = { type: 'INCREASE' } | { type: 'DECREASE' };  // 이렇게 액션을 | 으로 연달아서 쭉 나열하세요
    
    function reducer(state: number, action: Action): number {
        switch (action.type) {
            case 'INCREASE':
                return state + 1;
            case 'DECREASE':
                return state - 1;
            default:
                throw new Error('Unhandled action');
        }
    }
    
    function useReducerCounter() {
        const [count, dispatch] = useReducer(reducer, 0);
        const onIncrease = () => dispatch({ type: 'INCREASE' });
        const onDecrease = () => dispatch({ type: 'DECREASE' });
    
        return (
            <div>
                <h1>{count}</h1>
                <div>
                    <button onClick={onIncrease}>+1</button>
                    <button onClick={onDecrease}>-1</button>
                </div>
            </div>
        );
    }
    
    
    export default useReducerCounter;
    動作部では、|という文字を使用してORを表します.
    type Action = { type: 'INCREASE' } | { type: 'DECREASE' }; // 이렇게 액션을 | 으로 연달아서 쭉 나열하세요.
    最後に,上記のコードは動作のタイプが{type:"INCREASE"}または{type:"DECREASE"}であることを示す.
    上のコードのreduce関数のマットの前の行を確認しましょう.
    function reducer(state: number, action: Action): number
    見ると、stateのタイプと関数の戻りタイプは同じですよね?リダイレクトを作成する場合は、パラメータ形式で受信するタイプが関数で返されるタイプと同じであることを確認することが重要です.戻りタイプをステータスと同じタイプに設定することで、エラーを回避できます.(たとえば、ケースが結果値を返さなかったり、ステータスのタイプが変更されたりした場合、エラーが検出されます.)
    これで、アクションはtype値しかないので、非常に簡単です.アクションオブジェクトに他の必要な値がある場合は、タイプに他の値を明記してください.これにより、後続のプレゼンテーションを作成するときに、アクションオブジェクトに含まれる内容が自動的に完了します.また、新しいアクションを派遣するときに、アクションのタイプスクリプトタイプをチェックすることもできます.

    ReducerSampleの実装


    ReducerSampleというコンポーネントを作成して、自動完了とタイプチェックを直接チェックします.srcディレクトリにReducerSampleを作成します.tsxという名前のファイルを作成し、次のコードを実行します.コードの作成中に、コードが自動的に完了していることがわかります.必要な値が漏れている場合は、エラーが発生することもあります.

    src/ReducerSample.tsx

    import React, { useReducer } from 'react';
    
    type Color = 'red' | 'orange' | 'yellow';
    
    type State = {
      count: number;
      text: string;
      color: Color;
      isGood: boolean;
    };
    
    type Action =
      | { type: 'SET_COUNT'; count: number }
      | { type: 'SET_TEXT'; text: string }
      | { type: 'SET_COLOR'; color: Color }
      | { type: 'TOGGLE_GOOD' };
    
    function reducer(state: State, action: Action): State {
      switch (action.type) {
          case 'SET_COUNT':
              return {
                  ...state,
                  count: action.count // count가 자동완성되며, number 타입인걸 알 수 있습니다.
              };
          case 'SET_TEXT':
              return {
                  ...state,
                  text: action.text // text가 자동완성되며, string 타입인걸 알 수 있습니다.
              };
          case 'SET_COLOR':
              return {
                  ...state,
                  color: action.color // color가 자동완성되며, color 가 Color 타입이란걸 알 수 있습니다.
              };
          case 'TOGGLE_GOOD':
              return {
                  ...state,
                  isGood: !state.isGood
              };
          default:
              throw new Error('Unhandled action');
    
      }
    }
    
    function ReducerSample() {
      const [state, dispatch] = useReducer(reducer, {
          count: 0,
          text: 'hello',
          color: 'red',
          isGood: true
      });
    
      const setCount = () => dispatch({ type: 'SET_COUNT', count: 5 }); // count 를 넣지 않으면 에러발생
      const setText = () => dispatch({ type: 'SET_TEXT', text: 'bye' }); // text 를 넣지 않으면 에러 발생
      const setColor = () => dispatch({ type: 'SET_COLOR', color: 'orange' }); // orange 를 넣지 않으면 에러 발생
      const toggleGood = () => dispatch({ type: 'TOGGLE_GOOD' });
    
      return (
          <div>
              <p>
                  <code>count: </code> {state.count}
              </p>
              <p>
                  <code>text: </code> {state.text}
              </p>
              <p>
                  <code>color: </code> {state.color}
              </p>
              <p>
                  <code>isGood: </code> {state.isGood ? 'true' : 'false'}
              </p>
              <div>
                  <button onClick={setCount}>SET_COUNT</button>
                  <button onClick={setText}>SET_TEXT</button>
                  <button onClick={setColor}>SET_COLOR</button>
                  <button onClick={toggleGood}>TOGGLE_GOOD</button>
              </div>
          </div>
      );
    }
    export default ReducerSample;
    ステータス値が1つのオブジェクトで構成され、複数のタイプの値が含まれている場合は、上記のコードで作成したタイプ(Stateと呼ばれる)に基づいてタイプを準備できます.
    今回議論する動作はtype値だけでなくcount,text,colorのような他の値もある.この場合,再生器で自動的に完了し,開発に利便性を向上させ,動作の配布時にも動作のタイプチェックを行い,小さなエラーを回避するActionと呼ばれるスクリプトタイプを定義した.
    この構成部品をAPPでレンダリングし、各ボタンを押します.状態はちゃんと更新されていますか?

    App.tsx

    import React from 'react';
    import ReducerSample from './ReducerSample'
    
    function App() {
    return <ReducerSample />;
    };
    
    export default App;


    useRef


    userefは、外部ライブラリのインスタンスまたはDOMを応答素子の特定の値に配置するために使用される.また、これは、構成部品内部で管理される値を管理するのに役立ちます.ただし、この値はレンダリングとは無関係でなければなりません.

    変数値の管理


    タイプスクリプト環境でuserefで変数値を管理する場合は、次のコードを作成します.
    const id = useRef<number>(0);
     const increaseId = () => {
        id.current + 1;
    }
    userefを書くときは上のようにGenericを通ります現在の値を推定できます.

    管理DOM


    refにDOMが含まれている場合も同様です.ただし、初期値をnullに設定してください.MyFormコンポーネントを開き、handleSubmitイベントを登録するときに最初のInputに焦点を当てるように変更します.
    import React, { useState, useRef } from 'react';
    
    type MyFormProps = {
      onSubmit: (form: { name: string; description: string }) => void;
    };
    
    function Myform({ onSubmit }: MyFormProps) {
      const inputRef = useRef<HTMLButtonElement>(null);
    
      const [form, setForm] = useState({ name: '', description: '' });
    
      const { name, description } = form;
    
      const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
          const { name, value } = e.target;
          setForm({
              ...form,
              [name]: value
          });
      };
    
      const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
          e.preventDefault();
          onSubmit(form);
          setForm({
              name: '',
              description: ''
          }); //  초기화
          if (!inputRef.current) {
              return;
          }
          inputRef.current.focus();
      };
    
      return (
          <form onSubmit={handleSubmit}>
              <input name="name" value={name} onChange={onChange} />
              <input name="description" value={description} onChange={onChange} />
              <button type="submit">등록</button>
          </form>
      );
    }
    
    export default Myform;
    InputRefページコードでは、次のようにHTML InputElementタイプをGenericに挿入します.
    const inputRef = useRef<HTMLInputElement>(null);
    後でrefを使うときはどんなタイプを使うべきですか?混同されるかもしれません.この場合、エディタで必要なDOMにカーソルを合わせてください.

    では、どんなタイプを使うべきか簡単にわかります.(上の画像のドラッグ部分はタイプ名)
    また、inputRef.currentの値を使用する場合はnullチェックが必要です.つまり、値が本当に有効か無効かをチェックします.タイプがnullで定義されていないか、nullである可能性がある場合は、エラーが自動的に完了し、解消されるように、適切な値チェックを実行する必要があります.
    Appを開いてMyForm構成部品をレンダリングします.
    import React from 'react';
    import MyForm from './MyForm';
    
    function App() {
    const onSubmit = (form: { name: string; description: string }) => {
      console.log(form);
    };
    return <MyForm onSubmit={onSubmit} />;
    };
    
    export default App;

    整理する


    この授業で学んだ大切なことをまとめてみましょう.
  • usStateを使用する場合は、次のようにGenericsを使用します.
  • useState<String>
  • ユーザー・ワークステーションのGenericsは、状況に応じて省略できますが、ステータスが空の場合や、タイルまたは複雑なオブジェクトを処理する場合はGenericsを指定する必要があります.
  • UseReducerを使用する場合は、アクションのすべてのタイプのスクリプトを用意し、|文字を使用して組み合わせる必要があります.
  • スクリプト環境でUserReducerを使用すると、自動完了が実現され、タイプ化がサポートされます.
  • userRefを使用する場合は、Genericsを使用します.
  • userefを使用してDOMに関する情報を含む場合は、初期値をnullに設定し、nullフィルタを使用する必要があります.
  • 次のセクションでは、タイプスクリプト環境でContext APIを効率的に使用する方法について説明します.