Недооцененные хуки React

0 0

Если вы разработчик React и предпочитаете писать функциональные компоненты вместо классовых, то эта статья для вас; мы рассмотрим три полезных, но несколько недооцененных хука React, с которыми вы, возможно, не так хорошо знакомы: useImperativeHandle, useLayoutEffect и useDebugValue. Мы рассмотрим варианты их использования, синтаксис и несколько примеров кода. Давайте начнем!

React хук useImperativeHandle

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

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

Синтаксис:

Недооцененные хуки React

React JS. Основы

Изучите основы ReactJS на практическом примере по созданию учебного веб-приложения

Получить курс сейчас!

JavaScript useImperativeHandle(ref, createHandle, [dependencies])

1useImperativeHandle(ref, createHandle, [dependencies])

ref: ссылка, переданная от родительского компонента

createHandle: значение, которое будет предоставлено родительскому компоненту

dependencies: массив значений, который заставляет хук перезапускаться при изменении

Варианты применения

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

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

Определение состояния в родительском компоненте приведет к тому, что родительский компонент и его дочерние элементы будут повторно отображаться каждый раз при нажатии модальной кнопки, поэтому я хотел, чтобы состояние было в дочернем компоненте. Вместо этого я сохранил модальное состояние в модальном компоненте, используя useImperativeHandle и forwardRef. Рассмотрим код ниже:

JavaScript import React, { useRef } from ‘react’; import Child from ‘./Child’; const ParentComponent = () => { const childRef = useRef(null); const handleOpenModal = (value) => { childRef.current.openModal(value); } return ( <div> <p>This is a parent component</p> <Child ref={childRef}/> <button onClick={() => handleOpenModal(true)}>Open modal</button> </div> ) } export default ParentComponent;

123456789101112131415161718192021222324import React, { useRef } from ‘react’;import Child from ‘./Child’;  const ParentComponent = () => {     const childRef = useRef(null);     const handleOpenModal = (value) => {        childRef.current.openModal(value);    }      return (        <div>            <p>This is a parent component</p>            <Child ref={childRef}/>             <button onClick={() => handleOpenModal(true)}>Open modal</button>        </div>    ) } export default ParentComponent;

Выше мы определили ссылку, которую передали дочернему компоненту. В приведенном ниже коде ref будет первым параметром, переданным в useImperativeHandle.

Мы также определили функцию handleOpenModal, которая возвращает функцию openModal, переданную из дочернего компонента с помощью childRef.current.openModal(value). Эта функция вызывается при нажатии кнопки. Дочерний компонент должен выглядеть так, как показано ниже:

JavaScript import React, { forwardRef, useImperativeHandle, useState } from ‘react’; function ChildComponent (props, ref) { const [openModal, setOpenModal] = useState(false); useImperativeHandle(ref, () => ({ openModal: (value) => setOpenModal(value), })); if(!openModal) return null; return ( <div> <p>This is a modal!</p> <button onClick={() => setOpenModal(false)}> Close </button> </div> ) } export default forwardRef(ChildComponent);

123456789101112131415161718192021import React, { forwardRef, useImperativeHandle, useState } from ‘react’; function ChildComponent (props, ref) { const [openModal, setOpenModal] = useState(false);  useImperativeHandle(ref, () => ({  openModal: (value) => setOpenModal(value), }));   if(!openModal) return null;     return (        <div>            <p>This is a modal!</p>            <button onClick={() => setOpenModal(false)}> Close </button>        </div>    ) } export default forwardRef(ChildComponent);

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

React хук useLayoutEffect

Как и хук useEffect, хук useLayoutEffect позволяет выполнять дополнительные эффекты, такие как вызовы API, настройку подписок и манипулирование DOM вручную в функциональном компоненте.

Хотя React запускает как useEffect, так и useLayoutEffect после выполнения обновлений DOM, useLayoutEffect вызывается до того, как браузер отрисует эти обновления для просмотра пользователями, синхронно, а useEffect вызывается после того, как браузер отрисует эти обновления, асинхронно.

Таким образом, браузер не может отображать какие-либо обновления, пока не запустится useLayoutEffect. По этой причине вы в основном будете использовать useEffect, который выполняет роль показывает пользователям что-то вроде загрузчика в браузере, пока выполняются дополнительные эффекты.

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

Синтаксис:

JavaScript useLayoutEffect(callback, [dependencies])

1useLayoutEffect(callback, [dependencies])

callback: функция, содержащая логику побочного эффекта

dependencies: массив зависимостей.

Функция обратного вызова запускается снова при изменении значения любой из зависимостей. Рассмотрим код ниже:

JavaScript import React, { useState, useLayoutEffect, useEffect } from ‘react’; const TestHooks = () => { const [randomNumber, setRandomNumber] = useState(0); useEffect(() => { if (randomNumber === 0) { setRandomNumber(Math.random() * 1000); } }, [randomNumber]); return ( <div className=’App’> <p>{randomNumber}</p> <button onClick={() => setRandomNumber(0)}> Change value </button> </div> ); }; export default TestHooks;

1234567891011121314151617181920212223242526import React, {    useState,    useLayoutEffect,    useEffect  } from ‘react’;   const TestHooks = () => {    const [randomNumber, setRandomNumber] = useState(0);     useEffect(() => {    if (randomNumber === 0) {        setRandomNumber(Math.random() * 1000);    }  }, [randomNumber]);     return (        <div className=’App’>            <p>{randomNumber}</p>            <button onClick={() => setRandomNumber(0)}>                Change value             </button>        </div>    );  };   export default TestHooks;

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

Теперь замените useEffect на useLayoutEffect и снова нажмите кнопку. Переход к следующему случайному числу более плавный.

Код с использованием useEffect:

Код с использованием useLayoutEffect:

Вы можете поэкспериментировать с кодом, чтобы узнать больше.

Недооцененные хуки React

React JS. Основы

Изучите основы ReactJS на практическом примере по созданию учебного веб-приложения

Получить курс сейчас!

Варианты применения

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

Мы можем решить эту проблему с помощью useLayoutEffect следующим образом:

JavaScript import { useLayoutEffect } from “react”; import { useLocation } from “react-router-dom”; export default function ScrollToTop() { const { pathname } = useLocation(); useLayoutEffect(() => { window.scrollTo(0, 0); }, [pathname]); return null; }

123456789101112import { useLayoutEffect } from “react”;import { useLocation } from “react-router-dom”; export default function ScrollToTop() {  const { pathname } = useLocation();   useLayoutEffect(() => {    window.scrollTo(0, 0);  }, [pathname]);   return null;}

Файл index.js выглядит следующим образом:

JavaScript function Index() { return ( <Router> <ScrollToTop /> <App /> </Router> ); }

12345678function Index() {  return (    <Router>      <ScrollToTop />      <App />    </Router>  );}

По сути, мы сообщаем браузеру, что нужно направить пользователя на начало страницы, прежде чем показывать ему какой-либо контент. С помощью useLayoutEffect мы можем упростить этот процесс. Есть несколько других практических применений хука useLayoutEffect. После всех мутаций с DOM синхронно срабатывает useLayoutEffect; поэтому его можно использовать для чтения и изменения макета в DOM, от получения позиции прокрутки или других стилей для элемента до добавления анимации в определенную позицию прокрутки.

Однако будьте осторожны, ваш пользователь ничего не увидит, пока этот хук не будет запущен и не будет сделано обновление DOM.

React хук useDebugValue

В отличие от других рассмотренных нами хуков, которые используются для улучшения взаимодействия с пользователем, useDebugValue улучшает взаимодействие с разработчиком, помогая разработчикам регистрировать информацию в React DevTools в более простом формате. Обратите внимание, что хук useDebugValue следует использовать только в сочетании с пользовательским хуком React.

Синтаксис:

JavaScript useDebugValue(value)

1useDebugValue(value)

Если вы знакомы с React DevTools, то знаете, что всякий раз, когда встроенный хук React, такой как useState или useRef, используется в пользовательском хуке, он будет заниматся отладкой соответствующих значений в React DevTools.

Например, рассмотрим пользовательский хук ниже:

JavaScript import { useDebugValue, useState } from “react” export default function useCustomHook() { const [name, setName] = useState(“”) const [address, setAddress] = useState(“”) return [name, setName, address, setAddress] }

12345678import { useDebugValue, useState } from “react” export default function useCustomHook() {  const [name, setName] = useState(“”)  const [address, setAddress] = useState(“”)   return [name, setName, address, setAddress]}

Давайте вызовем пользовательский хук в App.js и проверим DevTools:

JavaScript import useCustomHook from ‘./useCustomHook’; function App() { useCustomHook(); return ( <> <div className=”App”> <p>hey</p> </div> </> ); } export default App;

12345678910111213141516import useCustomHook from ‘./useCustomHook’; function App() {   useCustomHook();   return (    <>    <div className=”App”>      <p>hey</p>    </div>    </>  );} export default App;

Проверяя React DevTools, мы видим, что значение для useState уже зарегистрировано для нас. У нас есть два состояния для name и address:

Недооцененные хуки React

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

Однако если бы мы создавали сложный пользовательский хук для использования в различных компонентах, нам понадобился бы способ отслеживать, какие значения принадлежат каким состояниям во время отладки. Для этого мы можем использовать useDebugValue для отображения метки для значений в пользовательских хуках в React DevTools. См. обновленный пользовательский хук ниже:

JavaScript import { useDebugValue, useState } from “react” export default function useCustomHook() { const [name, setName] = useState(“”) const [address, setAddress] = useState(“”) useDebugValue(name ? ‘Name has been set’ : ‘Name has not been set’) return [name, setName, address, setAddress] }

12345678910import { useDebugValue, useState } from “react” export default function useCustomHook() {  const [name, setName] = useState(“”)  const [address, setAddress] = useState(“”)   useDebugValue(name ? ‘Name has been set’ : ‘Name has not been set’)   return [name, setName, address, setAddress]}

Обновленный DevTools выглядит следующим образом:

Недооцененные хуки React

Мы можем отслеживать значение name по мере изменения его состояния, используя useDebugValue, поэтому нам не нужно угадывать, каково его значение. useDebugValue полезен, когда состояние хука не сразу видно в DevTools.

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

JavaScript useDebugValue(date, date => date.toDateString());

1useDebugValue(date, date => date.toDateString());

Заключение

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

UseImperativeHandleHook позволяет нам предоставлять значение, состояние или функцию внутри дочернего компонента родительскому компоненту. TheuseLayoutEffect позволяет нам выполнять дополнительные эффекты, такие как вызовы API, настройка подписок и ручное управление DOM в функциональном компоненте. Наконец, хук useDebugValue упрощает разработчикам регистрацию информации в React DevTools.

Теперь вы познакомились с этими специальными хуками React и знаете, как их использовать. Я надеюсь, что статья была полезной для вас!

Автор: Chiamaka Umeh

Источник: webformyself.com

Оставьте ответ