Кастомный хук для диспатчинга Redux экшенов
2 года назад·1 мин. на чтение
В этой статье напишем кастомный хук для вызова action creator’а Redux вместе с dispatch() внутри.
Часто, вызывая action creator, мы забываем обернуть его в
Допустим, мы работаем над приложением списка задач, и у нас есть действие
В компоненте вызов будет выглядеть следующим образом.
dispatch()
, а вместо этого вызываем как обычная функцию. Таким образом action не доходит до редьюсера.
Мы создадим собственный хук, в котором будет выполняться обертывание вызова функции вaddProductToCart(product); // не верно dispatch(addProductToCart(product)); // верно
dispatch()
, чтобы мы могли отправлять наши экшены, вызывая их как обычные функции с уже встроенным диспатчингом.
Реализация довольно проста.import { useCallback } from 'react'; import { useDispatch } from 'react-redux'; export const useWithDispatch = (fn) => { const dispatch = useDispatch(); return useCallback( payload => () => dispatch(fn(payload)), [dispatch, fn] ) }
useWithDispatch
— это функция высшего порядка, поскольку она принимает функцию (action creator) в качестве аргумента и возвращает другую функцию, которая при вызове вызовет переданную функцию, обернутую с помощью dispatch()
. Обязательно запоминаем функцию обратного вызова с помощью useCallback
.
addTask()
, которое берет текст задачи и добавляет его в список задач:
// actions.js const addTaskAction = (text) => { return { type: 'ADD_TASK', payload: { id: 'some-id', text } } }
import { addTaskAction } from './actions'; export const Component = () => { const addTask = useWithDispatch(addTaskAction); const handleClick = () => { addTask('Learn Redux'); } // ... }
Итоги
Я надеюсь, что вы нашли этот пост полезным. Вам по-прежнему нужно помнить о передаче создателей действий (action creator) вuseWithDispatch
, но будет легче запомнить, что вы делаете это в самом начале, а не при их вызове.5 кастомных React хуков, которые улучшат ваш код
2 года назад·3 мин. на чтение
В этой статье рассмотрим несколько очень полезных React хуков.
1. Хук useWindowSize
- хук для получения размера экрана
Я уверен, что в некоторых проектах, над которыми вы работали, вам нужно было получить ширину и высоту окна пользователя.
Так вот, теперь у вас есть хук для этого, так что вы можете сделать это еще проще, чем раньше.
Этот хук может быть особенно полезен при реализации отзывчивого дизайна, когда по какой-то причине вам нужно запустить определенный код при определенных размерах. Более продвинутый вариант этого хука можно найти в статье “Хук useResize для отслеживания ширины экрана в ReactJS”.import { useState, useEffect } from "react"; interface WindowSize { width: number; height: number; } const useWindowSize = (): WindowSize => { const [windowSize, setWindowSize] = useState<WindowSize>({ width: window.innerWidth, height: window.innerHeight, }); useEffect(() => { const handleResize = () => { setWindowSize({ width: window.innerWidth, height: window.innerHeight, }); }; window.addEventListener("resize", handleResize); return () => { window.removeEventListener("resize", handleResize); }; }, []); return windowSize; };
2️. Хук useKeyPress
- хук для определения нажатия клавиши
Следующий хук позволяет определить, когда нажата определенная клавиша. Это может вызвать события или действия, основанные на нажатой клавише. Например, для закрытия модального окна, отправки формы и т.д.
Пример использования:import { useState, useEffect } from "react"; const useKeyPress = (targetKey: string): boolean => { const [keyPressed, setKeyPressed] = useState(false); const downHandler = ({ key }: KeyboardEvent) => { if (key === targetKey) { setKeyPressed(true); } }; const upHandler = ({ key }: KeyboardEvent) => { if (key === targetKey) { setKeyPressed(false); } }; useEffect(() => { window.addEventListener("keydown", downHandler); window.addEventListener("keyup", upHandler); return () => { window.removeEventListener("keydown", downHandler); window.removeEventListener("keyup", upHandler); }; }, []); return keyPressed; };
const closeModalKeyPress = useKeyPress("Escape");
3. Хук useInterval
- хук для вызова функции setInterval
Этот хук позволяет вам использовать функцию setInterval
в качестве хука. Как и функция setInterval
, этот хук имеет множество применений, например, анимация, обновление данных через регулярные промежутки времени или даже установка таймера.
Можно использовать этот хук следующим образом:import { useState, useEffect, useRef } from "react"; const useInterval = (callback: () => void, delay: number | null) => { const savedCallback = useRef<() => void>(); useEffect(() => { savedCallback.current = callback; }, [callback]); useEffect(() => { function tick() { savedCallback.current && savedCallback.current(); } if (delay !== null && delay > 0) { let id = setInterval(tick, delay); return () => clearInterval(id); } else { tick(); } }, [delay]); };
const [count, setCount] = useState(0); useInterval(() => { setCount(count + 1); }, 1000);
4. Хук useDebounce
Теперь мы поговорим о хуке, который выполняет функцию только после того, как пройдет определенное количество времени без ее вызова.
Это полезно, например, для ограничения скорости вызовов API или обновления состояния при изменении ввода, например, когда вы набираете текст в поисковой строке.
Пример использования:import { useEffect, useRef } from 'react'; export function useDebounce(callback:Function, timeout: number = 200, deps: Array<any> = []) { const data = useRef({ firstTime: true }); useEffect(() => { const { firstTime, clearFunc } = data.current; const handler = setTimeout(() => { if (clearFunc && typeof clearFunc === 'function') { clearFunc(); } data.current.clearFunc = callback(); }, timeout); return () => { clearTimeout(handler); }; }, [timeout, ...deps]); } export default useDebounce;
const [inputValue, setInputValue] = useState(""); useDebounce(() => { // вызов APIl }, 500);
5️. Хук useThrottle
Throttle означает, что функция будет выполняться один раз за каждый заданный промежуток времени. Это может быть полезно для предотвращения быстрого запуска слишком большого количества вызовов API или событий.
Пример:import { useEffect, useRef } from 'react'; export const useThrottle = (callback:Function, delay: number = 200, deps: Array<any> = []) => { const lastRan = useRef(Date.now()); useEffect( () => { const handler = setTimeout(function() { if (Date.now() - lastRan.current >= delay) { callback(); lastRan.current = Date.now(); } }, delay - (Date.now() - lastRan.current)); return () => { clearTimeout(handler); }; }, [delay, ...deps], ); }; export default useThrottle;
Еще больше крутых хуков вы можете найти в каталоге хуков.const [inputValue, setInputValue] = useState(""); useThrottle(() => { // вызов API }, 500);