序章

フックはReactv16.8 の時点で安定しています! フック提案は、開発者がReactに関して抱えているいくつかの主要な懸念に対処する試みです。 基本的に、フックはReact機能に「フック」できる特別な機能です。 以前に機能コンポーネントを作成し、それに状態を追加する必要があることに気付いた場合、フックは理想的です。

Hooksを初めて使用し、概要を知りたい場合は、 ReactHooksの概要を確認してください。

useStateは、状態変数を宣言して、関数呼び出し間で値を保持します。 変数はReactによって保持されます。 useStateは、設定している状態の値を初期化する引数を1つだけ取ります。 useStateを実装することで、this.exampleが不要になり、変数に直接アクセスできるようになります。

このチュートリアルでは、以前に作成されたクラスベースのコンポーネントに基づいて構築し、useStateフックを使用してそれを機能コンポーネントに変換します。

前提条件

このチュートリアルは、ノードv16.4.0、npm v7.20.3、react v17.0.2、react-dom v17.0.2、react-scripts v4.0.3、 bootstrap v4.6.0、およびreactstrapv8.9.0。

ステップ1—プロジェクトの設定

このチュートリアルは、いくつかのスターターコードに基づいています。 スターターコードでは、最新バージョンのreactreact-dom、および reactstrap をインストールして、簡単にフォーマットできるようにしました。

コンポーネントは、emailおよびpasswordのフィールドを持つフォームで構成されています。 フォームが送信されると、値がコンソールに記録されます。

まず、ターミナルを開き、作業ディレクトリに移動します。 次に、リポジトリのクローンを作成します。

  1. git clone https://github.com/do-community/convert-class-to-hook

次に、新しいプロジェクトディレクトリに移動します。

  1. cd convert-class-to-hook

次に、パッケージの依存関係をインストールします。

  1. npm install

componentsディレクトリにある現在のClassBasedForm.jsコンポーネントについて理解してください。

src / components / ClassBasedForm.js
import React from 'react'
import {
  Form, FormGroup, Input,
  Label, Col, Button,
} from 'reactstrap'

export default class ClassBasedForm extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      email: '',
      password: '',
    }
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleSubmit(e) {
    e.preventDefault();
    console.log(this.state);
  }

  render() {
    return (
      <Form onSubmit={ this.handleSubmit }>
        <h1>Class-Based Form</h1>
        <FormGroup row>
          <Label for="exampleEmail" sm={ 2 }>Email</Label>
          <Col sm={ 8 }>
            <Input
              type="email"
              name="email"
              id="exampleEmail"
              placeholder="email"
              value={ this.state.email }
              onChange={ (event) => this.setState({ email: event.target.value }) }
            />
          </Col>
        </FormGroup>
        <FormGroup row>
          <Label for="examplePassword" sm={ 2 }>Password</Label>
          <Col sm={ 8 }>
            <Input
              type="password"
              name="password"
              id="examplePassword"
              placeholder="password"
              value={ this.state.password }
              onChange={ (event) => this.setState({ password: event.target.value })}
            />
          </Col>
        </FormGroup>
        <FormGroup check row>
          <Col sm={ { size: 'auto', offset: 8 } }>
            <Button>Submit</Button>
          </Col>
        </FormGroup>
      </Form>
    )
  }
};

最後に、アプリケーションを実行してインストールを確認します。

  1. npm start

ブラウザでアプリケーションを開きます。 メールアドレスとパスワードの値を入力し、フォームを送信します。

Screenshot of the application running in a browser with the class-based component.

この時点で、作業クラスベースのコンポーネントがあります。 クラスベースのコンポーネントを機能コンポーネントに変換する場合、この動作は変更されません。

ステップ2—機能コンポーネントの作成

このセクションでは、componentsフォルダーに追加のFormコンポーネントを作成します。 これはFunctionBasedForm.jsファイルになります。 このコンポーネントを使用して、useStateフックを使用して同じフォームを作成します。

クラスベースのコンポーネントと新しい機能コンポーネントを並べて使用すると、2つの実装を比較できます。

最初にReactをインポートし、テキストを返すFunctionBasedFormという関数変数を作成します。 必ずこの関数をエクスポートしてください。

src / components / FunctionBasedForm.js
import React from 'react';

const FunctionBasedForm = () => {
  return (
    <h1>Function Based Form</h1>
  )
};

export default FunctionBasedForm;

これをClassBasedForm.jsで使用されているclass ClassBasedForm extends React.Component { ... }宣言と比較してください。

次に、新しいコンポーネントをApp.jsに追加します。 コードエディタでApp.jsを開きます。

今のところ、以前のClassBasedFormインポートをコメントアウトします。

FunctionBasedFormコンポーネントをインポートします。 returnステートメントで、以前のコンポーネントを新しい<FunctionBasedForm />コンポーネントに置き換えます。

src / App.js
import React, { Component } from 'react';
import { Container } from 'reactstrap';
// import ClassBasedForm from './components/ClassBasedForm';
import FunctionBasedForm from './components/FunctionBasedForm';
import Logo from './assets/alligator-logo2.svg';
import './App.css';

class App extends Component {
  render() {
    return (
      <div className="App">
        <img src={ Logo } alt="alligator.io logo" width="200" />
        <Container>
          <FunctionBasedForm />
        </Container>
      </div>
    );
  }
}

export default App;

変更を保存して、アプリケーションを実行します。 次に、ブラウザでlocalhost:3000にアクセスします。

Screenshot of the application running in the browser with the functional component.

アプリケーションは、新しいコンポーネントからのテキストを表示します。

ステップ3—emailおよびpasswordの状態を追加する

元のClassBasedForm.jsコンポーネントでは、コンストラクターを使用して状態を初期化します。 通常のクラスコンポーネントで状態を初期化する必要はなく、フックも必要ありません。 次の例を考えてみましょう。

私たちのほとんどは、次のように状態を初期化することに精通しています。

constructor(props) {
  super(props);
  this.state = {
    email: '',
    password: '',
  };
}

React 16以降、コンストラクターは不要になりました。 前者は次のようになります。

state = {
  email: '',
  password: '',
};

機能コンポーネントで、フックを使用できるようになりました。 関数の開始時に、状態と関連するセッターを初期化できます。 これにより、数行のコードが削除される可能性があります。 新しいコンポーネントで状態変数を初期化する方法は次のとおりです。

const [email, setEmail] = useState('');
const [password, setPassword] = useState('');

上記の行の1つを分解してみましょう。

const [ email, setEmail] = useState('');
  • const:状態と関連する状態変数セッターの両方の変数を作成します。
  • email:最初の変数emailを初期化して宣言します。
  • setEmail:変数emailに関連付けられたセッター関数を初期化します。 冗長に見えるかもしれませんが、useStateは単一の値にのみ使用することを目的としています。
  • useState(''):変数emailが空の文字列として開始することを宣言します。

次に、コードエディタでFunctionBasedForm.jsに戻ります。

ClassBasedForm.jsからコードをコピーし、関数、クリックハンドラー、および状態変数を削除します。

次に、{ useState }をReactインポートに追加します。 また、前のセクションで定義した状態変数を追加します。

src / components / FunctionBasedForm.js
import React, { useState } from 'react';
import {
  Form, FormGroup, Input,
  Label, Col, Button,
} from 'reactstrap'

const FunctionBasedForm = () => {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  return (
    <Form>
      <h1>Function Based Form</h1>
      <FormGroup row>
        <Label for="exampleEmail" sm={ 2 }>Email</Label>
        <Col sm={ 8 }>
          <Input
            type="email"
            name="email"
            id="exampleEmail"
            placeholder="email"
          />
        </Col>
      </FormGroup>
      <FormGroup row>
        <Label for="examplePassword" sm={ 2 }>Password</Label>
        <Col sm={ 8 }>
          <Input
            type="password"
            name="password"
            id="examplePassword"
            placeholder="password"
          />
        </Col>
      </FormGroup>
      <FormGroup check row>
        <Col sm={ { size: 'auto', offset: 8 } }>
          <Button>Submit</Button>
        </Col>
      </FormGroup>
    </Form>
  )
};

export default FunctionBasedForm;

変更を保存して、ブラウザでアプリケーションにアクセスします。

Screenshot of the application running in the browser with the functional component.

この時点で、機能コンポーネントはクラスベースのコンポーネントと視覚的に同一です。

ステップ4—onChangeおよびhandleSubmitの機能を追加する

それでは、フックを利用するように関数を修正しましょう。

クラスベースのコンポーネントで状態を更新した方法をもう一度見てみましょう。

onChange={ (event) => this.setState({ email: event.target.value })

フックを使用すると、状態変数を開始してセッターをアタッチしているため、thisまたはthis.setState()は不要になります。

2つの変数があるため、インライン関数を使用して、入力ごとにuseStateで開始したセッターを呼び出します。 また、thisプレフィックスなしで値を追加し直します。

メールフィールドの場合:

<Input
  type="email"
  name="email"
  id="exampleEmail"
  placeholder="email"
  value={ email }
  onChange={ event => setEmail(event.target.value) }
/>

パスワードフィールドの場合:

<Input
  type="password"
  name="password"
  id="examplePassword"
  placeholder="password"
  value={ password }
  onChange={ event => setPassword(event.target.value) }
/>

それでは、handleSubmit関数を書き直してみましょう。

関数が以前に作成された方法は次のとおりです。

handleSubmit(e) {
  e.preventDefault();
  console.log(this.state);
}

注: React 16では、これを矢印関数として記述した場合、コンストラクターでバインドする必要はありません。

次に、関数のconstを作成する必要があります。 再びデフォルト機能を禁止し、変数を設定し、console.logそれらを設定します。

const handleSubmit = e => {
  e.preventDefault();
  console.log(email);
  console.log(password);
}

これで、handleSubmit関数をフォームのonSubmitに追加できます。

新しい機能フックは次のようになります。

src / components / FunctionBasedForm.js
import React, { useState } from 'react'
import {
  Form, FormGroup, Input,
  Label, Col, Button,
} from 'reactstrap'

const FunctionBasedForm = () => {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  const handleSubmit = event => {
    event.preventDefault();
    console.log(email);
    console.log(password);
  }

  return (
    <Form onSubmit={ handleSubmit }>
      <h1>Function Based Form</h1>
      <FormGroup row>
        <Label for="exampleEmail" sm={ 2 }>Email</Label>
        <Col sm={ 8 }>
          <Input
            type="email"
            name="email"
            id="exampleEmail"
            placeholder="email"
            value={ email }
            onChange={ event => setEmail(event.target.value) }
          />
        </Col>
      </FormGroup>
      <FormGroup row>
        <Label for="examplePassword" sm={ 2 }>Password</Label>
        <Col sm={ 8 }>
          <Input
            type="password"
            name="password"
            id="examplePassword"
            placeholder="password"
            value={ password }
            onChange={ event => setPassword(event.target.value) }
          />
        </Col>
      </FormGroup>
      <FormGroup check row>
        <Col sm={ { size: 'auto', offset: 8 } }>
          <Button>Submit</Button>
        </Col>
      </FormGroup>
    </Form>
  )
};

export default FunctionBasedForm;

変更を保存して、ブラウザでアプリケーションにアクセスします。

フォームにいくつかの値を追加し、送信ボタンを使用します。 開発ツールを開き、コンソールメッセージを表示します。 emailおよびpasswordの値が表示されます。

結論

このチュートリアルでは、以前に作成したクラスベースのコンポーネントに基づいて構築し、useStateフックを使用して機能コンポーネントに変換しました。

ReactプロジェクトにReactフックを適用する方法で学習を続けてください。