落とし穴

コンポーネントはクラスではなく関数として定義することをお勧めします。移行方法をご覧ください。

PureComponentComponentに似ていますが、同じ props と state の場合は再レンダリングをスキップします。クラスコンポーネントはReactでまだサポートされていますが、新しいコードでは使用しないことをお勧めします。

class Greeting extends PureComponent {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}

リファレンス

PureComponent

同じ props と state に対してクラスコンポーネントの再レンダリングをスキップするには、Componentの代わりにPureComponentを拡張します。

import { PureComponent } from 'react';

class Greeting extends PureComponent {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}

PureComponentComponentのサブクラスであり、すべてのComponent APIをサポートしています。PureComponentを拡張することは、props と state を浅く比較するカスタムshouldComponentUpdateメソッドを定義することと同じです。

以下の例をご覧ください。


使用方法

クラスコンポーネントの不要な再レンダリングをスキップする

React は通常、親が再レンダリングされるたびにコンポーネントを再レンダリングします。最適化として、新しい props と state が古い props と state と同じである限り、親が再レンダリングされても React が再レンダリングしないコンポーネントを作成できます。クラスコンポーネントは、PureComponent を拡張することで、この動作を選択できます。

class Greeting extends PureComponent {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}

Reactコンポーネントは、常に純粋なレンダリングロジックを持つ必要があります。これは、props、state、およびコンテキストが変更されていない場合、同じ出力を返さなければならないことを意味します。PureComponentを使用することにより、コンポーネントがこの要件に準拠していることを React に伝えるため、props と state が変更されていない限り、React は再レンダリングする必要がありません。ただし、使用しているコンテキストが変更された場合、コンポーネントは引き続き再レンダリングされます。

この例では、Greeting コンポーネントは name が変更されるたびに再レンダリングされます(それがpropsの一つであるため)。しかし、address が変更されても再レンダリングされません(Greeting にpropsとして渡されていないため)。

import { PureComponent, useState } from 'react';

class Greeting extends PureComponent {
  render() {
    console.log("Greeting was rendered at", new Date().toLocaleTimeString());
    return <h3>Hello{this.props.name && ', '}{this.props.name}!</h3>;
  }
}

export default function MyApp() {
  const [name, setName] = useState('');
  const [address, setAddress] = useState('');
  return (
    <>
      <label>
        Name{': '}
        <input value={name} onChange={e => setName(e.target.value)} />
      </label>
      <label>
        Address{': '}
        <input value={address} onChange={e => setAddress(e.target.value)} />
      </label>
      <Greeting name={name} />
    </>
  );
}

落とし穴

コンポーネントはクラスではなく関数として定義することをお勧めします。移行方法をご覧ください。


代替手段

PureComponent クラスコンポーネントから関数コンポーネントへの移行

新しいコードでは、クラスコンポーネントの代わりに、関数コンポーネントを使用することをお勧めします。PureComponent を使用している既存のクラスコンポーネントがある場合は、次のように変換できます。これが元のコードです。

import { PureComponent, useState } from 'react';

class Greeting extends PureComponent {
  render() {
    console.log("Greeting was rendered at", new Date().toLocaleTimeString());
    return <h3>Hello{this.props.name && ', '}{this.props.name}!</h3>;
  }
}

export default function MyApp() {
  const [name, setName] = useState('');
  const [address, setAddress] = useState('');
  return (
    <>
      <label>
        Name{': '}
        <input value={name} onChange={e => setName(e.target.value)} />
      </label>
      <label>
        Address{': '}
        <input value={address} onChange={e => setAddress(e.target.value)} />
      </label>
      <Greeting name={name} />
    </>
  );
}

このコンポーネントをクラスから関数に変換する場合は、memo でラップします:

import { memo, useState } from 'react';

const Greeting = memo(function Greeting({ name }) {
  console.log("Greeting was rendered at", new Date().toLocaleTimeString());
  return <h3>Hello{name && ', '}{name}!</h3>;
});

export default function MyApp() {
  const [name, setName] = useState('');
  const [address, setAddress] = useState('');
  return (
    <>
      <label>
        Name{': '}
        <input value={name} onChange={e => setName(e.target.value)} />
      </label>
      <label>
        Address{': '}
        <input value={address} onChange={e => setAddress(e.target.value)} />
      </label>
      <Greeting name={name} />
    </>
  );
}

注記

PureComponent とは異なり、memo は新しい状態と古い状態を比較しません。関数コンポーネントでは、set 関数 を同じ状態を使用して呼び出すと、デフォルトで再レンダリングが回避されますmemo がなくてもです。