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

В качестве примера рассмотрим простой компонент реакции, в котором пользователь вводит свое имя в поле ввода.

import React, { useState } from 'react';
export default function App() {
 const [name, setName] = useState('')
 return (
 <input
  type="text"
  value={name}
  onChange={e => setName(e.target.value)}
  />
 )
}

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

Создавая собственный хук, нужно начинать со слова «использовать», чтобы React мог творить чудеса за кулисами. В этом примере, поскольку мы надеемся работать с локальным хранилищем, давайте назовем имя файла, в котором мы будем создавать ловушку, «useLocalStorage.js».

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

export default function useLocalStorage() {
}

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

import React, { useState } from 'react';
export default function useLocalStorage() {
 const [value, setValue] = useState()
 return [value, setValue]
}

Теперь возвращаемое значение useLocalStorage точно такое же, как useState в самом первом примере выше.

Затем мы можем добавить новый хук и заменить хук useState:

import React from 'react';
import useLocalStorage from './useLocalStorage'
export default function App() {
 const [name, setName] = useLocalStorage('')
return (
 <input
  type="text"
  value={name}
  onChange={e => setName(e.target.value)}
  />
 )
}

Нам также необходимо определить свойство initialValue в useLocalStorage:

import React, { useState } from 'react';
export default function useLocalStorage(initialValue) {
 const [value, setValue] = useState(initialValue)
return [value, setValue]
}

На данный момент у нас есть настраиваемый хук, внутри которого заключено useState, однако он не очень полезен, поскольку не использует локальное хранилище ... пока!

Следующий шаг - убедиться, что наши данные сохраняются и могут быть получены через локальное хранилище:

import React, { useState } from 'react';
function getSavedValue(key, initialValue) //the key will be how it is stored in Local Storage
export default function useLocalStorage(key, initialValue) {
 const [value, setValue] = useState(initialValue)
return [value, setValue]
}

Также пошаговое обновление компонента App:

import React from 'react';
import useLocalStorage from './useLocalStorage'
export default function App() {
 const [name, setName] = useLocalStorage('name', '')
return (
 <input
  type="text"
  value={name}
  onChange={e => setName(e.target.value)}
  />
 )
}

Наше свойство key будет иметь значение name в локальном хранилище, давайте продолжим работу над функцией:

import React, { useState } from 'react';
function getSavedValue(key, initialValue) {
 const savedValue = JSON.parse(localStorage.getItem(key)
 // using the JSON.parse function converts the item to JSON
 if(savedValue) return savedValue //finds out if something has already been saved
 return initialValue
}
export default function useLocalStorage(key, initialValue) {
 const [value, setValue] = useState(initialValue)
return [value, setValue]
}

Если мы хотим, чтобы это работало так же, как useState, нам нужно будет изменить inout useState на функцию и проверить, является ли initial экземпляром функции:

import React, { useState } from 'react';
function getSavedValue(key, initialValue) {
 const savedValue = JSON.parse(localStorage.getItem(key)
 if(savedValue) return savedValue
 if (initialValue instanceof Function)return initialValue() 
 return initialValue
}
export default function useLocalStorage(key, initialValue) {
 const [value, setValue] = useState(() => {
  return getSavedValue(key, initialValue)
 })
return [value, setValue]
}

Изменение ввода useState в функцию приводит к тому, что она выполняется только один раз при рендеринге компонента.

Теперь нам нужно написать код для обновления и сохранения значения в локальном хранилище, и лучший способ сделать это - использовать useEffect.

import React, { useState, useEffect } from 'react';
function getSavedValue(key, initialValue) {
 const savedValue = JSON.parse(localStorage.getItem(key)
if(savedValue) return savedValue
if (initialValue instanceof Function)return initialValue()
return initialValue
}
export default function useLocalStorage(key, initialValue) {
 const [value, setValue] = useState(() => {
  return getSavedValue(key, initialValue)
})
useEffect(() => {
 localStorage.getItem(key, JSON.stringify(value)) //only strings can be passed to Local Storage
}, [value]) //hook runs when value changes
return [value, setValue]
}

Теперь наше входное значение может быть передано в локальное хранилище и получено!

Хотя приведенный выше код может быть сложным, имейте в виду, что все, что нам нужно сделать, чтобы использовать нашу извлеченную логику, - это просто импортировать useLocalStorage и настроить его так же, как и для useState или useEffect. В этом замечательная особенность пользовательских хуков: как только вся логика завершена, их очень просто использовать в любом компоненте, который вы хотите.