Перейти к содержанию

PureComponent

Мы рекомендуем определять компоненты как функции, а не как классы.

PureComponent похож на Component, но он пропускает повторные рендеринги для тех же пропсов и состояний. Компоненты классов по-прежнему поддерживаются React, но мы не рекомендуем использовать их в новом коде.

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

Описание

PureComponent

Чтобы пропустить повторное отображение компонента класса для тех же пропсов и состояния, расширьте PureComponent вместо Component:

1
2
3
4
5
6
7
import { PureComponent } from 'react';

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

PureComponent является подклассом Component и поддерживает все API Component Расширение PureComponent эквивалентно определению пользовательского метода shouldComponentUpdate, который неглубоко сравнивает пропсы и состояние.

Использование

Пропуск ненужных рендеров для компонентов классов

Обычно React перерисовывает компонент каждый раз, когда перерисовывается его родитель. В качестве оптимизации вы можете создать компонент, который React не будет перерисовывать при перерисовке его родителя до тех пор, пока его новые пропсы и состояние будут такими же, как старые пропсы и состояние. Класс компонентов может выбрать такое поведение, расширяя PureComponent:

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

Компонент React всегда должен иметь чистую логику рендеринга Это означает, что он должен возвращать тот же результат, если его пропсы, состояние и контекст не изменились. Используя PureComponent, вы сообщаете React, что ваш компонент соответствует этому требованию, поэтому React не нужно выполнять повторный рендеринг, пока его пропсы и состояние не изменились. Однако ваш компонент все равно будет перерендерирован, если контекст, который он использует, изменится.

В этом примере обратите внимание, что компонент Greeting перерисовывается при изменении name (потому что это один из его пропсов), но не при изменении address (потому что он не передается Greeting в качестве пропса):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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, вот как их можно преобразовать. Это оригинальный код:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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.

Ссылки

Комментарии