Поиск по сайту:

Как использовать состояние в функциональных компонентах React


Компоненты React могут иметь внутреннее «состояние» — набор пар ключ-значение, принадлежащих компоненту. Когда состояние изменяется, React повторно отображает компонент. Исторически состояние можно было использовать только в компонентах класса. Используя хуки, вы также можете применять состояние к функциональным компонентам.

Традиционный подход

Компоненты класса React имеют свойство state, которое хранит их состояние. Они предоставляют метод setState(), который вы можете использовать для обновления состояния, запуская повторный рендеринг.

class MyComponent extends React.Component {
 
    state = {value: 1};
 
    this.updateState = () => this.setState({value: (this.state.value + 1)});
 
    render() {
        return (
            <div>
                <p>{this.state.value}</p>
                <button onClick={this.updateState}Increment Value</button>
            </div>
        );
    }
 
}

В этом примере отображаемый текст всегда будет отображать число в состоянии компонента. Щелчок по кнопке увеличивает значение.

Преобразование в функциональный компонент

С таким простым компонентом было бы идеально переписать его как функциональный компонент. Для этого вам нужно использовать хук useState(). Хуки были добавлены в React 16.8; до этого выпуска не существовало механизма добавления состояния к функциональным компонентам.

Вот как вышеприведенный компонент выглядит как функциональный компонент:

import React, {useState} from "react";
 
const MyComponent = () => {
    const [value, setValue] = useState(1);
    return (
        <div>
            <p>{value}</p>
            <button onClick={() => setValue((value + 1))}>Increment Value</button>
        </div>
    );
};

Это короче и читабельнее, чем оригинал на основе классов. В отличие от компонента класса, вы не можете получить доступ к свойству экземпляра state или методу setState(). Вместо этого вызывается useState() для настройки состояния и получения функции обновления.

Анатомия хука useState()

Хуки — это функция React, которая позволяет вам «прицеплять» функциональность к функциональным компонентам. Поскольку функции являются чистыми и не имеют экземпляров, возможности, изначально реализованные как методы класса React.Component, нельзя использовать напрямую. Хуки позволяют добавлять эти функции в компоненты без необходимости преобразования в классы.

Хук useState() устанавливает отдельное свойство состояния. Он возвращает массив, содержащий два элемента: текущее значение состояния и функцию, которую вы можете вызвать с новым значением для обновления состояния.

В этом примере мы используем присваивание деструктуризации массива, чтобы распаковать значения массива в переменные с четкими именами. По соглашению метод установки должен иметь префикс set, так как он занимает место метода класса setState().

Вызов useState() объявляет переменную состояния, в нашем случае value, которая будет «сохраняться» между вызовами функций. Это означает, что useState() гарантированно возвращает одно и то же значение каждый раз, когда вы вызываете его в своем компоненте. Любое другое значение переменной теряется после выхода из функции; React поддерживает значения состояния внутри, чтобы гарантировать, что вы получаете одно и то же каждый раз, когда ваша функция запускается.

Обновление состояния

Функция обновления состояния — это обычная функция. Он используется в обработчике onClick для замены текущего значения состояния. Внутренняя обработка React значений состояния гарантирует, что ваш компонент будет повторно визуализирован. useState() предоставит новое значение, в результате чего произойдет изменение состояния.

Существует важное отличие от setState() компонентов класса: средства обновления функционального состояния заменяют состояние, тогда как setState() выполняет поверхностное слияние. :

const [value, setValue] = useState({foo: "bar", test: {example: "demo"}});
setValue({foo: "foobar"});
// Results in {foo: "foobar"}
 
this.state = {foo: "bar", test: {example: "demo"}};
this.setState({foo: "foobar"});
// Results in {foo: "foobar", test: {example: "demo"}};

Вместо прямой передачи нового значения состояния вы также можете передать функцию средствам обновления состояния. Функции получают текущее состояние в качестве параметра и должны возвращать новое значение состояния. Это полезно при работе с переключаемыми значениями.

const Checkbox = () => {
    const [checked, setChecked] = useState(false);
    const toggle = previous => !previous;
    return <input checked={checked} onClick={() => setChecked(toggle)} />;
};

Это поможет вам повторно использовать логику переключения в нескольких местах вашего компонента.

Значения по умолчанию

Есть еще одно замечание по поводу useState(). Сам хук принимает параметр, который устанавливает начальное значение переменной состояния. В приведенном выше примере value будет инициализировано равным 1. Если вы не указываете значение, используется undefined. Это соответствует поведению при настройке свойства экземпляра state в компоненте класса.

Если вы передадите функцию в useState(), React вызовет ее и будет использовать возвращаемое значение в качестве начального значения состояния.

const MyComponent = () => {
    const initialState = () => 1;
    const [value, setValue] = useState(initialState);
};

Этот метод позволяет «ленивую» инициализацию состояния. Функция не будет вызываться до тех пор, пока React не будет готов установить состояние.

Использование функции также гарантирует, что начальное значение состояния вычисляется только один раз. Это важно, если для определения вашего начального состояния требуются дорогостоящие вычисления — если вы передаете его напрямую, то значение будет вычисляться каждый раз при рендеринге компонента, по сравнению с одним разом при первом рендеринге, если вы передаете ссылку на функцию.

const MyComponent = () => {
    const doSomethingExpensive = () => {
        // ...
    }
    const [value, setValue] = useState(doSomethingExpensive());
    const [value, setValue] = useState(doSomethingExpensive);
};

Тонкая, но существенная разница в двух вызовах useState() иллюстрирует потенциальное улучшение производительности. Первая строка будет выполнять дорогостоящую операцию при каждом вызове рендеринга, даже если она будет избыточной, поскольку состояние уже инициализировано. Во втором случае этого не произойдет.

Использование нескольких значений состояния

У вас есть несколько вариантов использования нескольких значений состояния в одном функциональном компоненте. Вы можете вернуться к классовой системе, используя один объект, хранящийся в состоянии:

const MyComponent = () => {
    const [user, setUser] = useState({id: 1, username: "foobar"});
};

Вам нужно убедиться, что вы вызываете setUser() с обновленным пользовательским объектом. Синтаксис распространения полезен так же, как и компоненты класса:

setUser({...user, username: "example"});

Это создает новый объект с существующими свойствами user. Затем он обновляет свойство username до нового значения. Важно создать новый объект, а не напрямую изменять существующий объект, чтобы согласование состояния React могло идентифицировать изменение.

Кроме того, вы можете несколько раз вызвать useState(), чтобы настроить уникальные переменные состояния для каждого элемента. Это часто является предпочтительным подходом для функциональных компонентов. Это может упростить обновление отдельных значений состояния.

const MyComponent = () => {
    const [userId, setUserId] = useState(1);
    const [username, setUsername] = useState("foobar");
};

Свойства с состоянием теперь имеют свои собственные переменные состояния и функции обновления.

Заключение

Хук React useState() делает функциональные компоненты более мощными, позволяя им обладать состоянием. Вы можете установить начальное значение, получить доступ к текущему значению с гарантией, что оно сохранится между повторными рендерингами, и обновить состояние с помощью специально предоставленной функции.

Функциональные компоненты с состоянием часто пишутся быстрее, чем их аналоги на основе классов. Более того, они могут сделать более очевидным то, что происходит в вашей кодовой базе, поскольку ссылки на state и setState() исключаются в пользу четких имен переменных. В конечном счете, useState() обеспечивает гибкость и означает, что вам больше не нужно преобразовывать функциональные компоненты в компоненты класса в тот момент, когда вам требуется состояние.




Все права защищены. © Linux-Console.net • 2019-2024