落とし穴

クラスの代わりに関数でコンポーネントを定義することを推奨します。移行方法はこちら。

PureComponent は Component と似ていますが、同じ 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>;
}
}

PureComponent は Component のサブクラスであり、すべての 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 に伝えることができ、そのため React は props と state が変わらない限り再レンダーする必要がないと判断します。ただし、使用しているコンテクストが変更された場合、コンポーネントは再レンダーされます。

以下の例で、name が変更されるたびに 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 は新旧の state を比較しません。関数コンポーネントでは、同一の state 値で set 関数を呼び出した場合、memo がなくてもデフォルトで再レンダーが防止されます。