JavaScript популярен для функционального программирования. Существует несколько парадигм программирования, но три наиболее популярных - это функциональная, объектно-ориентированная (ООП) и процедурная.

Я не могу вдаваться в подробности из-за нехватки времени, но вот простой способ взглянуть на это:

Функциональное программирование разбивает проблемы на функции; объектно-ориентированное программирование разбивает проблемы на взаимодействующие объекты (смоделированные по образцу того, что мы называем классом); а процедурное программирование просто перечисляет шаги для решения проблемы в хронологическом порядке.

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

JavaScript любит функции! Вы можете работать в ООП с JS, но большинство программистов JS ненавидят классы. Фактически, под капотом каждый JS-класс на самом деле представляет собой функцию, выдающуюся за класс (реальная история).

Одной из неприятностей, с которыми столкнулись разработчики React, была невозможность привязать состояние (память) к функциональным компонентам. Это то, что React Hooks скоро изменит.

С помощью хуков вы можете воспроизвести практически все варианты использования состояния в функциональном компоненте и полностью отказаться от компонентов класса.

Чтобы наглядно проиллюстрировать, я собираюсь показать вам небольшую демонстрацию того, как я преобразовал существующий компонент класса в функциональный компонент в рабочем проекте React. Проект RoboFriends изначально создавался инструктором Udemy, Андреем Неагой.

Хотя это простой проект, вы, по крайней мере, должны хорошо разбираться в базовой терминологии React и JavaScript. Я не смогу объяснить каждый термин в этом коротком посте. Знание Git также будет полезно. Давайте погрузимся.

РобоДрузья

Исходный код можно найти в этом репозитории GitHub. Помните, что ссылка указывает на ветку react-hooks-start. Готовая работа находится на ветке react-hooks-end. Я намерен оставить эти ветки без изменений для использования в будущем.

Клонируйте репозиторий на свой локальный компьютер и выполните команду: npm install в каталоге.

Теперь мы хотим перейти к соответствующей ветке: git checkout react-hooks-start.

Затем запустите npm run start. Если все в порядке и у вас хорошее подключение к Интернету, перейдите по адресу localhost: 3000 в своем браузере, и вы увидите экран, подобный показанному ниже:

Если вы хотите построить это с нуля, я бы посоветовал вам попробовать любой из этих курсов Андрея на Удеми, в зависимости от вашего текущего уровня навыков. Это: Полный веб-разработчик в 2019 году: от нуля до мастерства и Полная дорожная карта веб-разработчика от младшего до старшего (2019). RoboFriends - лишь небольшая часть обоих курсов, но остальной материал курса чертовски хорош, если я сам так говорю.

Итак, все готово, но нам нужно сделать еще один важный шаг, прежде чем мы продолжим!

Согласно документации React, на момент написания этой статьи React Hooks находится в альфа-версии. Таким образом, вы не сможете использовать их в обычных выпусках react. На самом деле вам нужно обновить пакеты NPM до альфа-версии. Запустите это:

npm install --save [email protected] [email protected]

Это обновит версию React и React-DOM, используемую в вашем package.json. В будущем вам не придется делать это вручную.

РЕДАКТИРОВАТЬ: в наши дни хуки поставляются вместе с приложением Create-React-App. Вам больше не нужно вручную устанавливать версию React, чтобы использовать их.

Вы можете проверить, ничего ли не сломали.

Теперь весь наш код находится в папке src. Этот проект был создан с помощью create-react-app, поэтому структура каталогов довольно стандартная. В папке src вы найдете два подкаталога: компоненты и контейнеры. Компоненты нашего класса находятся в папке контейнеров: App.js и ErrorBoundary.js. Наши функциональные / не сохраняющие состояния / немые компоненты находятся в папке компонентов. Это просто условность.

Мы сосредоточимся на наших контейнерах. Помните, что мы хотим преобразовать компоненты нашего класса в функциональные компоненты с состоянием.

Вот как сейчас выглядит наш App.js:

Первое, что мы хотим сделать, это преобразовать класс в функцию:

class App extends Component{
   //our code
   ...
}

должен стать…

function App(){
   //our code
   ...
}

… Или, если хотите…

const App = () => {
   //our code
   ...
}

Если у вас включен ES Lint, он, вероятно, начнет жаловаться на ваш конструктор. Это просто потому, что у функций нет конструкторов. Все, что мы делаем в нашем коде конструктора, - это инициализируем состояние, поэтому давайте быстро воспользуемся хуками для замены конструктора:

//Swap out named component import for useState from 'react'
import React, { useState } from 'react';

function App(){
   //replace constructor function with these lines
   const [robots, setRobots] = useState([]);
   const [searchField, setSearchField] = useState('');

   //extra code
   ...
}

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

const [statefulVar, statefulVarSetter] = useState(initialArgForStatefulVar)

Если приведенный выше синтаксис выглядит забавно, мы используем концепцию JavaScript под названием деструктуризация массива. Это удобный ярлык.

ES Lint теперь жалуется на наш componentDidMount метод. React Hooks предоставляет нам ловушку, которая легко заменяет три метода жизненного цикла: componentDidMount, componentDidUpdate и componentWillUnmount.

Передай привет useEffect. Мы можем использовать useEffect вместо componentDidMount в нашем коде следующим образом:

//remember to import useEffect
import React, { useState, useEffect } from 'react';

function App(){
   //replace constructor function with these lines
   const [robots, setRobots] = useState([]);
   const [searchField, setSearchField] = useState('');

   useEffect(() => {
        fetch('https://jsonplaceholder.typicode.com/users')
        .then(res => res.json())
        .then(users => {
            //this.setState({ robots: users }) 
            //becomes:
            setRobots(users);
        });
   });

   //extra code
   ...
}

По сути, наш componentDidMount получил данные из API, преобразовал их в JSON (массив JSON) и присвоил этому массиву состояние robots с помощью this.setState. Мы делаем то же самое, но на этот раз используем setRobots.

useEffect просто берет функцию для запуска вместо componentDidMount и componentDidUpdate. Если у вас есть какая-либо функция, которую нужно очистить после компонента (что-то, что обычно должно быть в componentWillUnmount), просто верните эту функцию в конце useEffect. В этом небольшом примере нам не нужно этого делать.

Затем наш onSearchChange метод-обработчик может стать обычной функцией. Это уже стрелочная функция, поэтому давайте поставим перед ней const. Теперь мы изменим вызов this.setState внутри него, чтобы использовать метод установки, возвращаемый нашим обработчиком состояния. Вот что я имею в виду:

const onSearchChange = (event) => {
    setSearchField(event.target.value);
}

Последний важный блок - это наша функция рендеринга. Нам не нужна функция рендеринга в функциональном компоненте, поэтому вырежьте весь код из блока рендеринга и удалите вызов функции, а также его открывающую и закрывающую фигурные скобки.

Вставьте вырезанный вами код, и теперь мы можем удалить строку, которая гласит: const { robots, searchField } = this.state;

Мы можем удалить его, потому что robots и searchField уже являются переменными с состоянием, к которым мы можем получить доступ напрямую благодаря нашим useState вызовам в начале функции App.

Следующий блок, который представляет собой объявление и определение filteredRobots, вообще не изменяется, поскольку мы уже напрямую ссылаемся на переменную robots. Вы можете потратить некоторое время, чтобы убедиться, что это правда.

Наконец, наш оператор return выводит некоторый JSX в зависимости от количества роботов в нашем массиве robots. Мы используем тернарный оператор, но логика преобразуется в:
если robots.length равно нулю (т.е. ложь), мы выводим на экран «Загрузка ...». Если это не так, мы визуализируем некоторые компоненты: SearchBox и CardList, заключенные в компоненты ErrorBoundary и Scroll.

Нам нужно изменить только одно. Измените свойство, переданное в компонент SearchBox, с this.onSearchChange на onSearchChange со ссылкой на функцию-обработчик. Помните, что наши функциональные компоненты не должны иметь дело с "this".

То, что было нашим return блоком, теперь выглядит так:

const filteredRobots = robots.filter(robot => {
    return robot.name.toLowerCase().includes(searchField.toLowerCase())
});

return !robots.length ?
    <h1 className="tc">Loading...</h1> :
    (
        <div className='tc'>
            <h1 className='f1'>RoboFriends</h1>
            <SearchBox searchChange={onSearchChange} />
            <Scroll>
                <ErrorBoundary>
                    <CardList robots={filteredRobots} />
                </ErrorBoundary>
            </Scroll>
        </div>
    );

Если вас интересуют наши странные имена классов, в JSX мы используем библиотеку CSS под названием тахионы. Это действительно отличная библиотека.

Теперь наш полный код выглядит так:

Сохраните файл и убедитесь, что ничего не сломано.

Поздравляем !!! Наш код теперь работает, и я осмелюсь сказать, более читаемый и легкий для понимания.

Есть еще один компонент на основе классов: ErrorBoundary.js, но мы оставим его как компонент на основе классов.

Причина проста: на момент написания этого руководства у метода жизненного цикла componentDidCatch не было эквивалентной ловушки, и нам нужно использовать ее в нашем компоненте ErrorBoundary.

Вышеупомянутый пункт является свидетельством того, что Hooks все еще находятся в раннем возрасте. На момент написания этого руководства React Hooks все еще находились в альфа-версии. По словам основной команды React, они не намерены убирать классы из React, поэтому будьте уверены, ваши старые проекты на основе классов в безопасности.

Я надеюсь, что вам нравится React Hooks так же, как и мне. Если у вас есть какие-либо вопросы или проблемы, напишите мне в комментариях. Удачного кодирования!

Нокаут

Изначально опубликовано в Блоге KayO’s.