0 added
0 removed
Original
2026-01-01
Modified
2026-03-10
1
<p><strong><a>React Hooks</a></strong>- это долгожданные дополнения в React 16.8, с радостью встреченные сообществом React. Они являются полностью совместимыми с обычными подходами написания компонент.</p>
1
<p><strong><a>React Hooks</a></strong>- это долгожданные дополнения в React 16.8, с радостью встреченные сообществом React. Они являются полностью совместимыми с обычными подходами написания компонент.</p>
2
<p>Перед тем как рассматривать, что это такое, вспомним немного, как можно писать компоненты React.</p>
2
<p>Перед тем как рассматривать, что это такое, вспомним немного, как можно писать компоненты React.</p>
3
import React from 'react'; class Welcome extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; } }<p>Данный компонент является тем, что называется stateless, - у него отсутствует, что называется state, - любые данные, которые свойственны конкретному компоненту, которые меняются по собственному желанию.</p>
3
import React from 'react'; class Welcome extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; } }<p>Данный компонент является тем, что называется stateless, - у него отсутствует, что называется state, - любые данные, которые свойственны конкретному компоненту, которые меняются по собственному желанию.</p>
4
<p>Такие<strong>stateless-компоненты</strong>можно переписать в стрелочном виде:</p>
4
<p>Такие<strong>stateless-компоненты</strong>можно переписать в стрелочном виде:</p>
5
import React from 'react'; const Welcome = ({name}) => <h1>Hello, {name}</h1>;<p>Как можно увидеть, писать такие<strong>stateless-компоненты</strong>в стрелочном виде - огромное удовольствие. Но что делать с компонентами, которые имеют состояние? Например, с таким:</p>
5
import React from 'react'; const Welcome = ({name}) => <h1>Hello, {name}</h1>;<p>Как можно увидеть, писать такие<strong>stateless-компоненты</strong>в стрелочном виде - огромное удовольствие. Но что делать с компонентами, которые имеют состояние? Например, с таким:</p>
6
import React from 'react'; class Example extends React.Component { // Да, класс написан без наворотов babel - это для лучшего понимания ;) constructor(props) { super(props); this.state = { count: 0 }; } render() { const { count } = this.state; return ( <div> <p>You clicked {count} times</p> <button onClick={ () => this.setState({count: count + 1}) }> Click me </button> </div> ); } }<p>Обратите внимание, что для того, чтобы реализовать подобное состояние, необходимо: - проинициализировать начальное значение в конструкторе; - хранить этот count в state; - получать значение этого count в render; - и писать всё время this.setState(...), чтобы вызывать re-render при изменении state.</p>
6
import React from 'react'; class Example extends React.Component { // Да, класс написан без наворотов babel - это для лучшего понимания ;) constructor(props) { super(props); this.state = { count: 0 }; } render() { const { count } = this.state; return ( <div> <p>You clicked {count} times</p> <button onClick={ () => this.setState({count: count + 1}) }> Click me </button> </div> ); } }<p>Обратите внимание, что для того, чтобы реализовать подобное состояние, необходимо: - проинициализировать начальное значение в конструкторе; - хранить этот count в state; - получать значение этого count в render; - и писать всё время this.setState(...), чтобы вызывать re-render при изменении state.</p>
7
<p>И это ещё простой пример! В действительности код может быть куда сложнее, как минимум, с вынесенным методом изменения состояния.</p>
7
<p>И это ещё простой пример! В действительности код может быть куда сложнее, как минимум, с вынесенным методом изменения состояния.</p>
8
<p>Разберёмся, как этот компонент переписать с помощью<strong>React Hooks</strong>:</p>
8
<p>Разберёмся, как этот компонент переписать с помощью<strong>React Hooks</strong>:</p>
9
import React, { useState } from 'react'; const Example = () => { const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }<p>Обратите внимание, компонент написан в виде стрелочной функции.</p>
9
import React, { useState } from 'react'; const Example = () => { const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }<p>Обратите внимание, компонент написан в виде стрелочной функции.</p>
10
<h2>useState</h2>
10
<h2>useState</h2>
11
<p>Итак, useState:</p>
11
<p>Итак, useState:</p>
12
// Данная функция принимает начальное значение поля и возвращает специальный массив ... = useState(0);<p>Что возвращает:</p>
12
// Данная функция принимает начальное значение поля и возвращает специальный массив ... = useState(0);<p>Что возвращает:</p>
13
// useState возвращает массив из двух элементов - текущее состояние поля стейта // а ещё специальный метод - чтобы изменять состояние этого поля const [count, setCount] = useState(0);<p>Обратите внимание, что мы можем называть переменные для значения и метода, как хотим:</p>
13
// useState возвращает массив из двух элементов - текущее состояние поля стейта // а ещё специальный метод - чтобы изменять состояние этого поля const [count, setCount] = useState(0);<p>Обратите внимание, что мы можем называть переменные для значения и метода, как хотим:</p>
14
// Это всё корректно const [count, setCount] = useState(0); const [countValue, changeCount] = useState(0); const [c, updateCounter] = useState(0); const [userName, setUserName] = useState('Masha');<p>А дальше пользоваться этой переменной и методом можно вот таким образом:</p>
14
// Это всё корректно const [count, setCount] = useState(0); const [countValue, changeCount] = useState(0); const [c, updateCounter] = useState(0); const [userName, setUserName] = useState('Masha');<p>А дальше пользоваться этой переменной и методом можно вот таким образом:</p>
15
<!-- Вот здесь просто вывели значение переменной --> <p>You clicked {count} times</p> <!-- А вот здесь просто вызываем в обработчике --> <button onClick={() => setCount(count + 1)}><p>А что будет, если мы напишем несколько хуков?</p>
15
<!-- Вот здесь просто вывели значение переменной --> <p>You clicked {count} times</p> <!-- А вот здесь просто вызываем в обработчике --> <button onClick={() => setCount(count + 1)}><p>А что будет, если мы напишем несколько хуков?</p>
16
const [count, setCount] = useState(0); const [userName, setUserName] = useState('Masha');<p>Как ни странно,<strong>state</strong>не склеит эти два поля, и они будут изолированы. Как<strong>useState</strong>определит, что это два разных поля? Это просто - по порядку вызова. Ну, т. е. первый вызов useState вернёт значение и метод для “первого” поля, второй - значение и методы для “второго” и т. д.</p>
16
const [count, setCount] = useState(0); const [userName, setUserName] = useState('Masha');<p>Как ни странно,<strong>state</strong>не склеит эти два поля, и они будут изолированы. Как<strong>useState</strong>определит, что это два разных поля? Это просто - по порядку вызова. Ну, т. е. первый вызов useState вернёт значение и метод для “первого” поля, второй - значение и методы для “второго” и т. д.</p>
17
<p>Поэтому вводятся<strong>логичные практики</strong>: 1. Использовать хуки в корне компонента. 2. Не использовать хуки в циклах.</p>
17
<p>Поэтому вводятся<strong>логичные практики</strong>: 1. Использовать хуки в корне компонента. 2. Не использовать хуки в циклах.</p>
18
<p>Собственно, всё. Подведём промежуточные итоги: 1. Мы теперь можем писать компоненты со<strong>state</strong>и в стрелочном виде. 2. useState инициализирует поле state начальным значением. 3. useState берёт на себя обязанности по хранению поля state. 4. useState оборачивает вызов setState и предоставляет более удобный метод для изменения значения. Поэтому компонент обновится.</p>
18
<p>Собственно, всё. Подведём промежуточные итоги: 1. Мы теперь можем писать компоненты со<strong>state</strong>и в стрелочном виде. 2. useState инициализирует поле state начальным значением. 3. useState берёт на себя обязанности по хранению поля state. 4. useState оборачивает вызов setState и предоставляет более удобный метод для изменения значения. Поэтому компонент обновится.</p>
19
<p>Да и, разумеется, хуки нужно использовать только в функциональных компонентах.</p>
19
<p>Да и, разумеется, хуки нужно использовать только в функциональных компонентах.</p>
20
<h2>useEffect и другие</h2>
20
<h2>useEffect и другие</h2>
21
<p>Но и это не всё!</p>
21
<p>Но и это не всё!</p>
22
<p>Если мы хотим делать что-то дополнительное при обновлении компонента, то классический способ выглядел бы следующим образом:</p>
22
<p>Если мы хотим делать что-то дополнительное при обновлении компонента, то классический способ выглядел бы следующим образом:</p>
23
import React from 'react'; class Example extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } // вызываем callback на начальном значении componentDidMount() { const { onNewValue } = this.props; onNewValue(this.state); } // вызываем callback при изменении значения componentDidupdate() { const { onNewValue } = this.props; onNewValue(this.state); } render() { const { count } = this.state; return ( <div> <p>You clicked {count} times</p> <button onClick={ () => this.setState({count: count + 1}) }> Click me </button> </div> ); } }<p>Обратите внимание, что помимо длинного кода, мы ещё и получили необходимость перегружать два метода: componentDidMount чтобы обновить данные на первом рендере и componentDidUpdate чтобы обновить данные при последующих рендерах.</p>
23
import React from 'react'; class Example extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } // вызываем callback на начальном значении componentDidMount() { const { onNewValue } = this.props; onNewValue(this.state); } // вызываем callback при изменении значения componentDidupdate() { const { onNewValue } = this.props; onNewValue(this.state); } render() { const { count } = this.state; return ( <div> <p>You clicked {count} times</p> <button onClick={ () => this.setState({count: count + 1}) }> Click me </button> </div> ); } }<p>Обратите внимание, что помимо длинного кода, мы ещё и получили необходимость перегружать два метода: componentDidMount чтобы обновить данные на первом рендере и componentDidUpdate чтобы обновить данные при последующих рендерах.</p>
24
<p>Всё это можно объединить, используя хук useEffect:</p>
24
<p>Всё это можно объединить, используя хук useEffect:</p>
25
import React, { useState } from 'react'; const Example = ({onNewValue}) => { const [count, setCount] = useState(0); // Функция в аргументе вызовется на componentDidMount и componentDidUpdate useEffect(() => onNewValue(count)); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }<p>useEffect - это и есть способ задать componentDidMount и componentDidUpdate разом.</p>
25
import React, { useState } from 'react'; const Example = ({onNewValue}) => { const [count, setCount] = useState(0); // Функция в аргументе вызовется на componentDidMount и componentDidUpdate useEffect(() => onNewValue(count)); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }<p>useEffect - это и есть способ задать componentDidMount и componentDidUpdate разом.</p>
26
<p>Помимо всего прочего - useRef, useReducer, useContext, useCallback и useMemo. Ну и оставим читателям возможность самостоятельно изучить, как писать собственные хуки.</p>
26
<p>Помимо всего прочего - useRef, useReducer, useContext, useCallback и useMemo. Ну и оставим читателям возможность самостоятельно изучить, как писать собственные хуки.</p>
27
27