Как отмечалось в предыдущем посте, хуки - важная часть библиотеки 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. В этом замечательная особенность пользовательских хуков: как только вся логика завершена, их очень просто использовать в любом компоненте, который вы хотите.