Сложно ли будет настроить Hook с «вознаграждением за комментарии»?

внешний интерфейс Vue.js React.js

Эта статья участвовала в "Проект «Звезда раскопок»”, чтобы выиграть творческий подарочный пакет и бросить вызов творческим поощрительным деньгам.

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

Как новичок в React, я все еще немного боюсь пользовательских хуков.

Дождавшись выхода ведущего на работу, обсудите с ним: "Можете ли вы сначала пройти PR, а потом научиться настраивать крючки, а потом идти добывать".

Лидер спросил меня: «Какова функция Крюка?».

У меня был быстрый ответ: «Пусть функциональные компоненты имеют свое собственное состояние и жизненный цикл и используют функции React без использования классов».

Лидер серьезно сказал: «Вы забыли еще одну важную роль хука, упрощая повторное использование общей логики компонентов и избегая проблемы ада вложения, вызванного использованием HOC для повторного использования общей логики компонентов. Повторное использование логики Это важно, иначе это приведет к большому количеству повторяющегося кода в проекте. Я этого не приемлю. Вы должны использовать пользовательский хук для извлечения общей логики нескольких компонентов перед отправкой PR».

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

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

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

Что такое кастомный хук

Пользовательский хук — это функция, имя которой начинается с «use" в начале внутри функции могут быть вызваны другие хуки.

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

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

  • Имя функции:к "use", например useState. Зачем начинать с "use". Это потому, что если оно не начинается с "use” в начале нет способа определить, содержит ли эта функция вызов своего внутреннего хука, и React не сможет автоматически проверить, не нарушает ли этот пользовательский хук правила хука.

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

  • внутри функции: Другие хуки могут быть вызваны внутри функции, но необходимо соблюдать два правила:

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

    • Не вызывайте хуки в обычных функциях JavaScript, только в функциях React. Это легко понять, сам хук предоставляется React.

  • возвращаемое значение: Нет ограничений на то, что должно быть возвращено, конечно, функция возвращает значение по умолчанию.undefined.

Сцена с пользовательским хуком

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

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

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

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

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

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

Настройте простейший хук

const Demo = () =>{
  useEffect(() => {
     console.log('组件首次渲染')
  },[]);
}
export default Demo;

Вышеописанное определенно является наиболее распространенной логикой в ​​компоненте.useEffectВторой параметр получает пустой массив, чтобы указать, что он будет выполняться только при первом рендеринге компонента.useEffectМетоды. Затем мы поместим эту общую логику, настроив именованныйuseMountХук извлекается и реализуется следующим образом:

import { useEffect } from 'react';

const useMount = (fn: () => void) => {
  useEffect(() => {
    fn();
  }, []);
};

export default useMount;

useMountЭта пользовательская функция приема хукаfnВ качестве аргумента выполнить функцию при первом рендеринге компонентаfn.

Как использовать пользовательские хуки

Пользовательский хук определяется в файле js или ts и, наконец, используетсяexportэкспортировать, использоватьimportИмпортировать с помощью:

import useMount from '@/hooks/useMount';

const Demo = () =>{
  useMount(() =>{
     console.log('组件首次渲染')
  })
  return(
    <div>demo</div>
  )
}
export default Demo;

Внутренности кастомного крючка

React предоставляет внутренние крючки 10. Внутри пользовательских крючков эти 10 внутренних крючков обычно используются для сборки и расширения для настройки крючков различных функций.

У новичков здесь часто возникает вопрос, например, в кастомном хукеuseMyStateиспользуется вuseStateопределяетaПеременная.

import { useState } from 'react';

const useMyState = () => {
 const [a,setA] = useState();
 return [a,setA]
};

export default useMyState;

затем используяuseMyИспользование в компонентахuseStateопределяетaпеременные, это не вызовет конфликтов.

import useMyState from '@/hooks/useMount';

const Demo = () =>{
  const [a,setA] = useState();
  const [b,setB] = useMyState();
  return(
    <div>demo</div>
  )
}
export default Demo;

Не беспокойтесь об этом, два хука полностью изолированы и могут использоваться несколько раз в одном компоненте.useStateа такжеuseEffect, они полностью независимы. И Hook — это тоже функция с областью действия внизу.

Теперь, когда вопрос снят, как я могу использовать 10 внутренних хуков для настройки нового хука. Чтобы привести очень простой пример, мы хотим отобразить значение до того, как значение изменится во время разработки. Обычно это делается:

const Demo = () =>{
  const [current , setCurrent ] = useState(1);
  const [previous , setPrevious ]= useState(0);
  const updata = () => {
    setCurrent(value =>{
      setPrevious(value);
      return value+1;
    })
  }
  return (
    <div>
      <div>{current}</div>
      <div>{previous}</div>
      <div onClick={updata}>改变</div>
    </div>
  );
}
export default Demo

которые используют дваuseStateсоздал текущийcurrentи доpreviousдвух переменных, изменяяcurrentкогда, поставитьcurrentПредыдущее значение присваиваетсяprevious. Хотя этого можно добиться, это немного неэлегантно.currentСделайте некоторые суждения о предыдущем значении, а затем присвойте егоprevious, это меняетсяcurrentизsetCurrentВ методе нужно прописать много несвязанных вещей, что немного противоречит единому принципу.

В настоящее время мы можем настроить хук для работы с этим бизнес-сценарием, я назвал этот хук какusePrevious.

import { useRef } from 'react';
const usePrevious = (state, compare) =>{
  const prevRef = useRef();
  const curRef = useRef();

  const needUpdate = typeof compare === 'function' ? compare(curRef.current, state) : true;
  if (needUpdate) {
    prevRef.current = curRef.current;
    curRef.current = state;
  }

  return prevRef.current;
}

export default usePrevious;

который используетuseRefдля хранения старых и новых значений значения по сравнению с предыдущимuseStateчтобы сохранить его. причина в томuseRefвернуть изменяемыйrefобъект, которыйcurrentСвойства инициализируются переданными параметрами. вернутьrefОбъекты остаются неизменными в течение всего срока службы компонента.

когдаrefКогда содержание объекта меняется,useRefи не уведомит вас. то есть изменить.currentсвойства не вызывают повторную визуализацию компонента,Это важно, иuseStateЛюбое изменение созданного значения вызовет повторную визуализацию компонента.

HookusePreviousпринять данныеstateи функцияcompare, функцияcompareСтарое значение и новое значение полученных данных можно оценить в функции, прежде чем решить, следует ли присвоить ихprevRef.current, КрюкusePreviousпоследнее возвращениеprevRef.current.

как использоватьusePreviousНу пример выглядит так:

import usePrevious from '@/hooks/usePrevious';
const Demo = () =>{
  const [current , setCurrent ] = useState(1);
  const compare = (oldValue,newValue) =>{
     if(oldValue !== newValue){
       return true;
     }
  }
  const previous = usePrevious(current,compare);
  const updata = () => {
    setCurrent(value =>{
      value = value + 1;
      return value;
    })
  }
  return (
    <div>
      <div>{current}</div>
      <div>{previous}</div>
      <div onClick={updata}>改变</div>
    </div>
  );
}
export default Demo

Есть ли необходимая связь между пользовательским хуком и внутренним хуком React?

На этом этапе давайте подумаем над другим вопросом: должны ли мы использовать внутренний хук React для разработки собственного хука?

Ответ, конечно, нет. Зачем? давайте посмотрим еще разusePreviousиспользование,usePreviousне какuseStateПредоставляет способ обновить значение, так почемуusePreviousВозвращаемое значениеpreviousбудет обновляться в режиме реального времени.

Речь идет о характеристиках функциональных компонентов.Тело функции функциональных компонентов является телом компонента класса.render(), когда состояние или реквизиты компонента изменяются, компонент будет повторно визуализирован, а тело функции функционального компонента будет выполнено повторно.

тогда, когдаcurrentпри смене,DemoЭта функция будет выполняться снова, покаconst previous = usePrevious(current,compare);,usePreviousПолучить новыйcurrent, который, естественно, возвращает новыйprevious, поэтому он обновляется в режиме реального времени.

Итак, теперь настройте хукuseMyCountСледующим образом:

const useMyCount = (state) =>{
  return state + 1;
}

export default useMyCount;

Возможен ли этот пользовательский хук? Давайте использовать его.

import useMyCount from '@/hooks/usePrevious';
const Demo = () =>{
  const [num , setNum ] = useState(1);
  const count = useMyCount(num);
  const updata = () => {
    setNum(value =>{
      value = value + 1;
      return value;
    })
  }
  return (
    <div>
      <div>{num}</div>
      <div>{count}</div>
      <div onClick={updata}>加一</div>
    </div>
  );
}
export default Demo

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

Другой пример — мой пользовательский хук, который получает текущую временную метку:

const useTime = () =>{
  return new Date().getTime();
}

export default useTime;

Настройте хук, который запрашивает список задач:

import * as Api from '@/api'
const useTask = async () =>{
  const res = await Api.getTask();
  return res;
}

export default useTask;

Ни один из этих пользовательских хуков не использует внутренние хуки React.Так что настроить хук не сложно.

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

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

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

И последнее, но не менее важное: обратите внимание, что хук отвечает только за одно — следовать одному принципу.

  • Требования к параметрам

    • нет параметров

      Разрешить хуки без параметров.

      const time = useTime();
      
    • один параметр

      Отдельный параметр вводится напрямую, независимо от того, требуется он или нет.

      const a = useA(parame);
      
    • Несколько обязательных параметров

      Требуемых параметров меньше 2, и их следует вводить на том же уровне.

      const a = useA(parame1, parame2);
      

      Если их больше 2, их следует вводить как объект.

      const a = useA( {parame1:1, parame2:2, parame3:3 } );
      
    • Множество необязательных параметров

      Многие необязательные параметры вводятся в виде объекта.

      const a = useA({parame1?, parame2?, parame3?, parame4?});
      
      
    • Обязательный параметр + необязательный параметр

      Обязательные параметры идут первыми, а необязательные параметры идут после.

      const a = useA(parame,{parame1?, parame2?, parame3?, parame4?});
      
      
  • Требования к структурам возвращаемых значений

    • нет выхода

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

      useMount(() => {});
      
    • тип значения

      Вывод хуков имеет только одно значение.

      const a = useA();
      
    • тип значения setValue

      Выходное значение имеет тип value и setValue, а структура — [value, setValue] .

      const [state, setState] = useA(a);
      
    • тип действия значения

      Где действия — это методы манипулирования данными.

      Выходное значение имеет одно значение и несколько типов действий, а структура — [значение, действия] .

      const [value, { actions1, actions2, actions3}] = useA(...);
      
    • тип значений

      Выходное значение имеет несколько типов значений и имеет структуру {...values}

      const {value1, value2, value3} = useA();
      
    • значения тип действия

      Выходное значение состоит из нескольких значений и нескольких типов действий, а структура имеет вид {...values, ...actions} .

      const {value1, value2, actions1, actions2} = useA(...);
      

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

Эпилог

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

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

«Добро пожаловать для обсуждения в области комментариев, официальный представитель NuggetsПроект «Звезда раскопок»После мероприятия в комментариях будет разыграно 100 штук Наггетсов.Подробнее о лотерее читайте в статье о мероприятии»..