Пошаговое руководство по созданию первого React Hook

Пошаговое руководство по созданию первого React Hook

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

Что такое React Hooks?

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

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

Основные встроенные хуки React

Перед созданием собственного хука полезно ознакомиться с некоторыми из наиболее часто используемых встроенных хуков:

  • useState: Позволяет добавлять состояние в функциональные компоненты.
  • useEffect: Используется для выполнения побочных эффектов в функциональных компонентах.
  • useContext: Предоставляет доступ к контексту React.
  • useReducer: Альтернатива useState для управления сложным состоянием.
  • useCallback: Возвращает мемоизированную версию колбэк-функции.
  • useMemo: Мемоизирует вычисляемое значение.

Подготовка к созданию пользовательского хука

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

Необходимые предварительные знания

Для успешного создания и использования пользовательских хуков, разработчику следует иметь:

  • Базовое понимание JavaScript и ES6+
  • Опыт работы с React и функциональными компонентами
  • Знакомство с основными встроенными хуками React
  • Понимание концепции замыканий в JavaScript

Настройка среды разработки

Для начала работы над пользовательским хуком потребуется следующее:

  • Node.js и npm (или yarn) установленные на компьютере
  • Редактор кода (например, Visual Studio Code, Sublime Text или WebStorm)
  • Создание нового React-проекта или использование существующего

Если у разработчика еще нет React-проекта, он может создать его с помощью Create React App:

npx create-react-app custom-hook-tutorial cd custom-hook-tutorial npm start

Шаг 1: Определение цели пользовательского хука

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

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

Применение useToggle

Хук useToggle может быть полезен в различных сценариях, например:

  • Переключение видимости модальных окон
  • Управление состоянием «развернуть/свернуть» для аккордеонов
  • Включение/выключение определенных функций интерфейса

Шаг 2: Создание файла для пользовательского хука

Следующим шагом является создание отдельного файла для пользовательского хука. Это поможет организовать код и сделает хук легко импортируемым в другие компоненты.

В директории src проекта следует создать новую папку hooks и внутри нее файл useToggle.js:

mkdir src/hooks touch src/hooks/useToggle.js

Шаг 3: Написание базовой структуры хука

Теперь можно приступить к написанию базовой структуры хука useToggle. Вот начальный код для файла useToggle.js:

import { useState } from 'react';
const useToggle = (initialState = false) => {
const [state, setState] = useState(initialState);

const toggle = () => {
setState(prevState => !prevState);
};

return [state, toggle];
};

export default useToggle;

Давайте разберем этот код:

  • Импортируется хук useState из React для управления состоянием.
  • Определяется функция useToggle, которая принимает необязательный параметр initialState со значением по умолчанию false.
  • Внутри хука используется useState для создания состояния и функции его обновления.
  • Определяется функция toggle, которая инвертирует текущее состояние.
  • Хук возвращает массив, содержащий текущее состояние и функцию toggle.

Шаг 4: Использование пользовательского хука в компоненте

Теперь, когда базовая структура хука готова, можно использовать его в компоненте. Для демонстрации создадим простой компонент ToggleButton.

Создайте новый файл src/components/ToggleButton.js со следующим содержимым:

import React from 'react'; import useToggle from '../hooks/useToggle';
const ToggleButton = () => {
const [isOn, toggleIsOn] = useToggle();

return (

);
};

export default ToggleButton;

В этом компоненте:

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

Шаг 5: Тестирование пользовательского хука

Чтобы убедиться, что пользовательский хук работает корректно, следует протестировать его в реальном приложении. Обновите файл src/App.js, чтобы включить компонент ToggleButton:

import React from 'react'; import ToggleButton from './components/ToggleButton';
function App() {
return (

Custom Hook: useToggle

);
}

export default App;

Теперь при запуске приложения должна отображаться кнопка, которая переключается между состояниями «ON» и «OFF» при нажатии.

Шаг 6: Расширение функциональности хука

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

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

Вместо использования фиксированных значений true и false, можно позволить пользователям задавать собственные значения для состояний «включено» и «выключено».

Обновите файл useToggle.js следующим образом:

import { useState } from 'react';
const useToggle = (initialValue = false, onValue = true, offValue = false) => {
const [value, setValue] = useState(initialValue);

const toggle = () => {
setValue(currentValue =>
currentValue === onValue ? offValue : onValue
);
};

return [value, toggle];
};

export default useToggle;

Теперь хук принимает три параметра:

  • initialValue: начальное значение (по умолчанию false)
  • onValue: значение для состояния «включено» (по умолчанию true)
  • offValue: значение для состояния «выключено» (по умолчанию false)

Использование расширенного хука

Обновите компонент ToggleButton, чтобы использовать новые возможности хука:

import React from 'react'; import useToggle from '../hooks/useToggle';
const ToggleButton = () => {
const [mood, toggleMood] = useToggle('😊', '😊', '😢');

return (

);
};

export default ToggleButton;

Теперь кнопка будет переключаться между смайликами «😊» и «😢» вместо «ON» и «OFF».

Шаг 7: Добавление дополнительных функций

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

Обновите файл useToggle.js следующим образом:

import { useState, useCallback } from 'react';
const useToggle = (initialValue = false, onValue = true, offValue = false) => {
const [value, setValue] = useState(initialValue);

const toggle = useCallback(() => {
setValue(currentValue =>
currentValue === onValue ? offValue : onValue
);
}, [onValue, offValue]);

const setOn = useCallback(() => setValue(onValue), [onValue]);
const setOff = useCallback(() => setValue(offValue), [offValue]);

return [value, toggle, setOn, setOff];
};

export default useToggle;

В этой версии хука:

  • Добавлены функции setOn и setOff для прямой установки состояния.
  • Использован хук useCallback для мемоизации функций, чтобы избежать ненужных ререндеров.

Использование расширенного хука с дополнительными функциями

Теперь можно обновить компонент ToggleButton, чтобы использовать новые функции:

import React from 'react'; import useToggle from '../hooks/useToggle';
const ToggleButton = () => {
const [mood, toggleMood, setHappy, setSad] = useToggle('😐', '😊', '😢');

return (

Current mood: {mood}



);
};

export default ToggleButton;

Шаг 8: Документирование пользовательского хука

Важным аспектом создания пользовательского хука является его документирование. Это поможет другим разработчикам (или вам самим в будущем) понять, как использовать хук и какие у него есть возможности.

Добавьте JSDoc комментарии к файлу useToggle.js:

import { useState, useCallback } from 'react';
/**

Пользовательский хук для переключения между двумя значениями.
@param {*} initialValue - Начальное значение состояния.
@param {*} onValue - Значение для состояния "включено".
@param {*} offValue - Значение для состояния "выключено".
@returns {Array} Массив, содержащий:
Текущее значение состояния
Функция для переключения состояния
Функция для установки состояния в значение "включено"
Функция для установки состояния в значение "выключено" */ const useToggle = (initialValue = false, onValue = true, offValue = false) => { const [value, setValue] = useState(initialValue);
const toggle = useCallback(() => {
setValue(currentValue =>
currentValue === onValue ? offValue : onValue
);
}, [onValue, offValue]);

const setOn = useCallback(() => setValue(onValue), [onValue]);
const setOff = useCallback(() => setValue(offValue), [offValue]);

return [value, toggle, setOn, setOff];
};

export default useToggle;

Шаг 9: Оптимизация производительности

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

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

Можно использовать хук useMemo для мемоизации возвращаемого массива, чтобы предотвратить ненужные перерендеры компонентов, использующих этот хук:

import { useState, useCallback, useMemo } from 'react';
const useToggle = (initialValue = false, onValue = true, offValue = false) => {
const [value, setValue] = useState(initialValue);

const toggle = useCallback(() => {
setValue(currentValue =>
currentValue === onValue ? offValue : onValue
);
}, [onValue, offValue]);

const setOn = useCallback(() => setValue(onValue), [onValue]);
const setOff = useCallback(() => setValue(offValue), [offValue]);

return useMemo(() => [value, toggle, setOn, setOff], [value, toggle, setOn, setOff]);
};

export default useToggle;

Шаг 10: Обработка ошибок и валидация

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

import { useState, useCallback, useMemo } from 'react';
const useToggle = (initialValue = false, onValue = true, offValue = false) => {
if (onValue === offValue) {
throw new Error('onValue и offValue не должны быть одинаковыми');
}

const [value, setValue] = useState(() => {
if (initialValue !== onValue && initialValue !== offValue) {
console.warn('initialValue должно быть равно onValue или offValue. Используется значение по умолчанию.');
return offValue;
}
return initialValue;
});

const toggle = useCallback(() => {
setValue(currentValue =>
currentValue === onValue ? offValue : onValue
);
}, [onValue, offValue]);

const setOn = useCallback(() => setValue(onValue), [onValue]);
const setOff = useCallback(() => setValue(offValue), [offValue]);

return useMemo(() => [value, toggle, setOn, setOff], [value, toggle, setOn, setOff]);
};

export default useToggle;

Шаг 11: Создание unit-тестов

Тестирование является важной частью разработки надежных и поддерживаемых хуков. Давайте создадим несколько unit-тестов для нашего хука useToggle.

Создайте файл useToggle.test.js в той же директории, где находится useToggle.js:

import { renderHook, act } from '@testing-library/react-hooks'; import useToggle from './useToggle';
describe('useToggle', () => {
test('should initialize with default values', () => {
const { result } = renderHook(() => useToggle());
expect(result.current[0]).toBe(false);
});

test('should toggle between true and false', () => {
const { result } = renderHook(() => useToggle());
act(() => {
result.current1;
});
expect(result.current[0]).toBe(true);
act(() => {
result.current1;
});
expect(result.current[0]).toBe(false);
});

test('should set on and off values', () => {
const { result } = renderHook(() => useToggle(false, 'on', 'off'));
expect(result.current[0]).toBe('off');
act(() => {
result.current2; // setOn
});
expect(result.current[0]).toBe('on');
act(() => {
result.current3; // setOff
});
expect(result.current[0]).toBe('off');
});

test('should throw error if onValue equals offValue', () => {
expect(() => {
renderHook(() => useToggle(false, 'same', 'same'));
}).toThrow('onValue и offValue не должны быть одинаковыми');
});
});

Для запуска этих тестов потребуется установить необходимые зависимости:

npm install --save-dev @testing-library/react-hooks

Шаг 12: Интеграция с TypeScript

Если проект использует TypeScript, можно добавить типизацию для хука useToggle, чтобы улучшить поддержку IDE и обеспечить дополнительную проверку типов.

Переименуйте файл useToggle.js в useToggle.ts и обновите его содержимое:

import { useState, useCallback, useMemo } from 'react';
type ToggleValue = any;

interface UseToggleReturn {
value: ToggleValue;
toggle: () => void;
setOn: () => void;
setOff: () => void;
}

function useToggle(
initialValue: ToggleValue = false,
onValue: ToggleValue = true,
offValue: ToggleValue = false
): UseToggleReturn {
if (onValue === offValue) {
throw new Error('onValue и offValue не должны быть одинаковыми');
}

const [value, setValue] = useState(() => {
if (initialValue !== onValue && initialValue !== offValue) {
console.warn('initialValue должно быть равно onValue или offValue. Используется значение по умолчанию.');
return offValue;
}
return initialValue;
});

const toggle = useCallback(() => {
setValue(currentValue =>
currentValue === onValue ? offValue : onValue
);
}, [onValue, offValue]);

const setOn = useCallback(() => setValue(onValue), [onValue]);
const setOff = useCallback(() => setValue(offValue), [offValue]);

return useMemo(() => ({
value,
toggle,
setOn,
setOff
}), [value, toggle, setOn, setOff]);
}

export default useToggle;

Шаг 13: Создание примеров использования

Чтобы помочь другим разработчикам понять, как использовать хук useToggle, можно создать несколько примеров использования в различных сценариях.

Пример 1: Простое переключение

import React from 'react'; import useToggle from './useToggle';
const SimpleToggle = () => {
const { value, toggle } = useToggle();

return (

);
};

export default SimpleToggle;

Пример 2: Переключение с пользовательскими значениями

import React from 'react'; import useToggle from './useToggle';
const CustomValueToggle = () => {
const { value, toggle } = useToggle('Привет', 'Привет', 'Пока');

return (

);
};

export default CustomValueToggle;

Пример 3: Использование setOn и setOff

import React from 'react'; import useToggle from './useToggle';
const ControlledToggle = () => {
const { value, toggle, setOn, setOff } = useToggle();

return (

Состояние: {value ? 'Включено' : 'Выключено'}



);
};

export default ControlledToggle;

Шаг 14: Публикация хука

Если хук получился достаточно универсальным и полезным, его можно опубликовать как отдельный npm-пакет, чтобы другие разработчики могли легко использовать его в своих проектах.

Подготовка к публикации

  1. Создайте новую директорию для пакета и инициализируйте npm-проект: mkdir use-toggle-hook cd use-toggle-hook npm init -y
  2. Скопируйте файл useToggle.ts в новую директорию.
  3. Создайте файл index.ts: export { default } from './useToggle';
  4. Обновите package.json: { "name": "use-toggle-hook", "version": "1.0.0", "description": "A custom React hook for toggling between two values", "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { "build": "tsc", "prepublishOnly": "npm run build" }, "keywords": ["react", "hook", "toggle", "custom-hook"], "author": "Your Name", "license": "MIT", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" }, "devDependencies": { "@types/react": "^18.0.0", "typescript": "^4.5.0" } }
  5. Создайте файл tsconfig.json: { "compilerOptions": { "target": "es5", "module": "commonjs", "declaration": true, "outDir": "./dist", "strict": true, "jsx": "react", "esModuleInterop": true }, "include": ["src"], "exclude": ["node_modules", "**/__tests__/*"] }

Публикация пакета

  1. Убедитесь, что у вас есть аккаунт на npmjs.com
  2. Войдите в свой npm-аккаунт в терминале: npm login
  3. Опубликуйте пакет: npm publish

Заключение

Создание пользовательского React Hook — это мощный способ инкапсулировать и переиспользовать логику в React-приложениях. Следуя этому пошаговому руководству, разработчик может создать свой первый пользовательский хук, протестировать его, оптимизировать и даже опубликовать для использования другими разработчиками.

Вот краткое резюме основных шагов, которые были рассмотрены:

  1. Определение цели хука
  2. Создание базовой структуры
  3. Реализация основной логики
  4. Тестирование хука в компоненте
  5. Расширение функциональности
  6. Оптимизация производительности
  7. Добавление обработки ошибок и валидации
  8. Написание unit-тестов
  9. Интеграция с TypeScript
  10. Создание примеров использования
  11. Публикация хука как npm-пакета

Создание пользовательских хуков — это навык, который совершенствуется с практикой. Чем больше хуков создает разработчик, тем лучше он понимает, как эффективно инкапсулировать и переиспользовать логику в React-приложениях.

Рекомендуется продолжать экспериментировать с созданием различных пользовательских хуков для решения конкретных задач в проектах. Это не только улучшит код, но и поможет глубже понять принципы работы React и функционального программирования в целом.

Дальнейшие шаги

После освоения создания базовых пользовательских хуков, можно рассмотреть следующие направления для развития:

  • Создание более сложных хуков, комбинирующих несколько встроенных хуков React
  • Изучение паттернов композиции хуков
  • Исследование возможностей оптимизации производительности с помощью хуков
  • Создание хуков для работы с внешними API и библиотеками
  • Разработка хуков для управления сложными формами
  • Изучение взаимодействия хуков с контекстом React

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

Читайте также  Положительное влияние обновленного Gutenberg на эффективность сайта
Советы по созданию сайтов