[React]Hook


React Hook公式ドキュメントトレースされたレスポンスホストのパージ

React Hookが登場した背景


クラス構成部品ステータス管理の複雑さと限界

componentDidMountcomponentDidUpdatecomponentWillUnmounなど.
ライフサイクルによっては、関連するコードが分離され、関連のないコードがメソッドに結合されます.
ライフサイクル法に基づいて分割するよりも、同様のコンポーネントをHookで小関数配列として使用することもできます.

クラス構成部品のステータス管理の再使用


Reactは、再利用可能な論理をコンポーネント間に貼り付ける方法を提供していない.したがって、独立したテストと再利用は困難ですが、Hookはステータスに関連する論理を抽象化し、レイヤを変更せずにステータスに関連する論理を再使用するのに役立ちます.

クラス内のthisキーワード


クラス構成部品の使用時に使用されるJavaScriptthisキーワードは、他の多くの言語とは異なり、コードの作成時に混乱や重複使用の問題が発生します.
したがって,関数型素子における「Hook」の使用は,クラスがない場合に「React」機能をどのように使用するかを示す.

State Hookの使用

// 클래스형 컴포넌트
class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}
Hookを使用して、上記のクラス構成部品を関数型構成部品として作成できます.
// 동일한 기능을 하는 Hook을 사용한 함수형 컴포넌트
import React, { useState } from 'react';

function Example() {
  // 새로운 state 변수를 선언하고, count라 부르겠습니다.
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
対応する関数型構成部品では、useStateはHookです.useStateは、現在のstate値と、その値を更新する関数とをペアリングします.
const [현재의_state 값, 이_값을_업데이트하는__함수] = useState(초기_state);
useState関数が宣言する関数はclassのthisです.setStateとほぼ似ていますが、前のstateと新しいstateがマージされていないという違いがあります.
初期stateはclassのthisです.stateとは異なり、オブジェクトである必要はありません.もちろん客体かもしれません.

複数のステータス変数の宣言

function ExampleWithManyStates() {
  // 상태 변수를 여러 개 선언했습니다!
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
  // ...
}
レンダーするたびに、ReactはusStateで使用される順序で実行されます.

ステータスの更新


クラス構成部品は、countをリフレッシュするためにthis.setState()を呼び出す.
ただし、関数要素にはsetCount変数とcount変数があり、thisを呼び出す必要はありません.

Effect Hookの使用


Reactionのclassライフサイクルメソッドに精通している場合は、UserEffect HookをコンポーネントDidMountとコンポーネントDidUpdate、コンポーネントWillUnmountの組合せと見なすことができます.
データのインポート、サブスクリプションの設定から反応素子を手動で変更するDOMまで、これらはすべて副作用であり、関数型素子で副作用を実行するのがuseEffect Hookである.
一般的には2つの副作用があります.
1.クリーンアップ(clean-up):ネットワーク要求、DOM手動操作、ログ記録[メモリリークに注目]
2.クリーンアップ不要:外部データの購読が必要な場合は、[メモリの漏洩に注意]

1.Clean-upを使用しないEffects


応答プログラムはDOMを更新した後に追加のコードを実行する必要がある場合がある.実行してから心配することはないからです.

クラスの例


反応器のクラス素子ではrender法自体が副作用を生じない.この時点ではまだ早いが,これは反応器がDOMを更新した後である.
これは反応器において,副作用をComponentDidMountとComponentDidUpdateに置くためである.
// class 컴포넌트 
// 리액트가 DOM을 바꾸고 난 뒤 타이틀 업데이트
class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  componentDidMount() {
    document.title = `You clicked ${this.state.count} times`;
  }
  componentDidUpdate() {
    document.title = `You clicked ${this.state.count} times`;
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}
上記のコードでは、2つのライフサイクルメソッドが同じコードを繰り返します.
これは、インストールフェーズでも更新フェーズでも重複を回避することはできません.

Hookの例

import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
userEffect Hookは、伝達された関数(「effect」と呼ばれる)を覚えた後にDOM更新を実行します.
データをインポートしたり、他のコマンド型APIを呼び出したりすることもできます.
userEffectを構成部品の内部に保持することで、effectを使用してcount state変数(または任意のprops)にアクセスできます.
関数の範囲内に存在すると、値が得られます.
レンダリングするたびにuserEffectが実行されます.既定では、最初のレンダリングとその後のすべての更新で実行されます.(必要に応じて効果を変更できます.)反応器は、効果の実行時にDOMが更新されたことを保証する.

2.Clean-upのEffectsを使う


たとえば、外部データを購読する必要がある場合は、clean-upを行ってメモリの漏洩を避けることが重要です.

クラスの例


反応クラスは、通常、componentDidMountにサブスクリプションを設定し、componentWillUnmountでクリーンアップする.
// 클래스형 컴포넌트
// 친구의 온라인 상태를 구독할 수 있는 ChatAPI 모듈의 예를 들어보겠습니다. 
// 다음은 class를 이용하여 상태를 구독(subscribe)하고 보여주는 코드입니다.

class FriendStatus extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isOnline: null };
    this.handleStatusChange = this.handleStatusChange.bind(this);
  }

  componentDidMount() {
    ChatAPI.subscribeToFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }
  componentWillUnmount() {
    ChatAPI.unsubscribeFromFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }
  handleStatusChange(status) {
    this.setState({
      isOnline: status.isOnline
    });
  }

  render() {
    if (this.state.isOnline === null) {
      return 'Loading...';
    }
    return this.state.isOnline ? 'Online' : 'Offline';
  }
}
componentDidMountおよびcomponentWillUnmountのコードは概念的に同じ効果を有するが、ライフサイクルメソッドはそれを分離する.

Hookの例


Hookを使用して、上記の機能を持つコードを作成しましょう.Clean-upを実行するには、異なる効果が必要だと思います.しかし、サブスクリプションの追加と削除に使用されるコードの結合度が高いため、useEffectはそれらを同時に処理するように設計されている.effectが関数を返すと、reactionはクリーンアップが必要なときに関数を実行します.
import React, { useState, useEffect } from 'react';

function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    // effect 이후에 어떻게 정리(clean-up)할 것인지 표시합니다.
    return function cleanup() {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}
効果から関数を返します.その原因は、効果を達成するために付加されたクリーンアップメカニズムである.すべての効果は、クリーンアップに使用する関数を返します.この点は、追加および削除ロジックを緊密に縛り付けます.
コンポーネントのアンインストール時にクリーンアップを実行するように応答します.ただし、効果は1回ではなく、レンダリングの実行時に実行されます.これは、リアクターが次の効果を実行する前に、以前のレンダリングから派生した効果を整理する理由です.

ヒント:Effectをスキップしてパフォーマンスを最適化


すべてのレンダリング後に効果を適用すると、パフォーマンスが低下することがあります.
これらの問題は、クラス要素について、componentDidUpdateprePropsまたはPrevStateと比較することによって解決することができる.
componentDidUpdate(prevProps, prevState) {
  if (prevState.count !== this.state.count) {
    document.title = `You clicked ${this.state.count} times`;
  }
}
これらの要件は一般的であるため、userEffectは選択的な2回目の買収によって管理することもできる.
useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // count가 바뀔 때만 effect를 재실행합니다.
上記の例では、[count]を第2のファクタに移動する.countが5であり、素子が再レンダリングされた後もcountが変わらない場合、リアクターは前のレンダリング時の値[5]を次のレンダリング時の[5]と比較する.アレイ内のすべての値が同じであるため、(5 === 5)reactionは効果をスキップします.このような最適化は可能である.
countが6に更新されてレンダリングされると、反応器は、以前にレンダリングされた値[5]をレンダリング時の[6]と比較する.この場合(5 !== 6)であるため、反応器は効果を再実行する.アレイ内に複数の値がある場合、いずれかの値が異なる場合でも、反応器は効果を再実行します.
すなわち,配列中のデータ(state,props)が変更された場合にのみ効果が実行される.
useEffect(() => {
  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

  ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
  return () => {
    ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
  };
}, [props.friend.id]); // props.friend.id가 바뀔 때만 재구독합니다.
2番目のパラメータが空の配列[]を超えると、効果のpropsとstateは初期値を維持します.

Hookは最上階からしか呼び出せません。繰り返し文、条件文、ネスト関数でHookを実行しないでください

Hook APIリファレンス