9102, как фронтенд, ты должен уметь играть хуком

внешний фреймворк

задний план

Для меня большая честь участвовать в vueconf, состоявшемся в Шанхае 8 июня. Во введении vue3.0, объясненном самим Ю Да, я увидел некоторые новые функции vue3.0. Один из самых важных RFCVue Function-based API RFC, случайно, я только недавно исследовал этоreact hook, я чувствую, что у них одна и та же цель в мышлении, поэтому я хочу обобщить идею о хуках. В то же время я вижу, что введение многих людей о хуках обсуждается отдельно. Конечно, это может быть то же самое, что и vue3 .0 для этой функции Это означает, что она имеет определенное отношение к только что вышедшей, так что давайте начнем~

что такое крючок

Прежде всего, нам нужно понять, что такое хук.Принимая во внимание введение реакции, его определение:

Это позволяет вам использовать состояние и другие функции React без написания классов.

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

class Hello extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() { // do sth... }

  componentWillUnmount() { // do sth... }
  
  // other methods or lifecycle...
  
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

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

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

react не предоставляет некоторые методы работы для установки состояния и жизненного цикла в функциональных компонентах, поэтому в то время было удобно использовать функциональные компоненты в очень немногих сценариях, но ситуация изменилась после того, как в версии 16.8 появились хуки, и цель крючки это--Позволяет использовать состояние и другие функции React без написания классов, чтобы увидеть пример:

import React, { useState } from 'react';

function Example() {
  // 声明一个新的叫做 “count” 的 state 变量
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

useState — это хук, предоставляемый react, с помощью которого мы можем установить желаемое состояние в функциональном компоненте, которое можно не только использовать, но и легко передать через setState (обратите внимание, что это не setState в классе, что относится к приведенному выше примеру setCount) изменение в , конечно же, react предоставляет множество хуков для поддержки различных поведений и операций, мы кратко представим их ниже, мы смотрим на хук vue, это фрагмент кода, которым Youda поделился на vueconf:

import { value, computed, watch, onMounted } from 'vue'

const App = {
  template: `
    <div>
      <span>count is {{ count }}</span>
      <span>plusOne is {{ plusOne }}</span>
      <button @click="increment">count++</button>
    </div>
  `,
  setup() {
    // reactive state
    const count = value(0)
    // computed state
    const plusOne = computed(() => count.value + 1)
    // method
    const increment = () => { count.value++ }
    // watch
    watch(() => count.value * 2, val => {
      console.log(`count * 2 is ${val}`)
    })
    // lifecycle
    onMounted(() => {
      console.log(`mounted`)
    })
    // expose bindings on render context
    return {
      count,
      plusOne,
      increment
    }
  }
}

Из приведенного выше примера нетрудно увидеть, что использование хука реакции очень похоже, и Ю Да также сказал, что этот RFC заимствует идею хука реакции, но избегает некоторых проблем с реакцией, а затем объясните, почему я поместил это в vue RFC также называется ловушкой, потому что во введении к хуку реакции есть такое предложение, что такое хук — хук — это функция, которая позволяет вам «перехватывать» состояние React и функции жизненного цикла в функциональных компонентах, а затем vue функции этих предоставленных API-интерфейсов аналогичны — вы можете «подцепить» функциональные компоненты в функциональных компонентах с такими функциями, как значение (данные в 2.x) и жизненный цикл, поэтому давайте пока назовем это vue-hook~

Эра значимости крюка

Итак, каково значение эпохи крючков? Фреймворк с самого начала служит бизнесу, и одна из проблем, которую сложно избежать в бизнесе, это - повторное использование логики, одна и та же функция, один и тот же компонент, в разных случаях нам иногда приходится писать 2+ раза, в Чтобы избежать связывания, основные фреймворки предложили несколько решений:

  • mixin
  • HOC
  • slot

Использование основных фреймворков:

  • И react, и vue использовали примеси (react в настоящее время устарел),
  • Компоненты высшего порядка (HOC) относительно больше используются в React, а для vue немного вложенных шаблонов. . неловко,
  • Слот vue используется больше, реагировать в основном не нужно использование слота,

Все вышеперечисленные методы могут обеспечить логическое повторное использование, но все они имеют некоторые дополнительные проблемы:

  • Проблемы с миксинами:

    • Могут быть взаимозависимыми и связанными, что не способствует сопровождению кода;
    • Методы в разных миксинах могут конфликтовать друг с другом;
    • Когда миксинов много, компоненты воспринимаются, и для них даже нужно делать соответствующую обработку. Это может усложнить код как снежный ком.
  • Проблемы с ХОЦ:

    • Его нужно обернуть или вложить в исходный компонент.Если вы часто используете HOC, Будет много вложенности, что сильно усложнит отладку;
    • HOC может украсть реквизит, а также может вызвать конфликты, если контракт не соблюдается.
    • PROPS также может вызывать конфликты имен.
    • wrapper hell

Вы когда-нибудь видели такую ​​структуру дома?

Это типичный представитель оберточного ада~

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

  1. повторное использование логического кода
  2. Уменьшенный размер кода
  3. Не беспокойтесь об этом

С учетом этих идей давайте посмотрим на реагирование на реагирование и VUE соответственно:

Введение в реагирующие хуки

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

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

import React, { Component } from 'react';

export default class MyClassApp extends Component {
    constructor(props) {
        super(props);
        this.state = {
            x: 0,
            y: 0
        };
        this.handleUpdate = this.handleUpdate.bind(this);
    }
    componentDidMount() {
        document.addEventListener('mousemove', this.handleUpdate);
    }
    componentDidUpdate() {
        const { x, y } = this.state;
        document.title = `(${x},${y})`;
    }
    componentWillUnmount() {
        window.removeEventListener('mousemove', this.handleUpdate);
    }
    handleUpdate(e) {
        this.setState({
            x: e.clientX,
            y: e.clientY
        });
    }
    render() {
        return (
            <div>
                current position x:{this.state.x}, y:{this.state.y}
            </div>
        );
    }
}

Онлайн-демонстрация кода наздесь

Та же логика, которую мы используем для достижения

import React, { useState, useEffect } from 'react';

// 自定义hook useMousePostion
const useMousePostion = () => {
    // 使用hookuseState初始化一个state
    const [postion, setPostion] = useState({ x: 0, y: 0 });
    function handleMove(e) {
        setPostion({ x: e.clientX, y: e.clientY });
    }
    // 使用useEffect处理class中生命周期可以做到的事情
    // 注:效果一样,但是实际的原理并不同,有兴趣可以去官网仔细研究
    useEffect(() => {
        // 同时可以处理 componentDidMount 以及 componentDidUpdate 中的事情
        window.addEventListener('mousemove', handleMove);
        document.title = `(${postion.x},${postion.y})`;
        return () => {
            // return的function 可以相当于在组件被卸载的时候执行 类似于 componentWillUnmount
            window.removeEventListener('mousemove', handleMove);
        };
        // [] 是参数,代表deps,也就是说react触发这个hook的时机会和传入的deps有关,内部利用objectIs实现
        // 默认不给参数会在每次render的时候调用,给空数组会导致每次比较是一样的,只执行一次,这里正确的应该是给postion
    }, [postion]);
    // postion 可以被直接return,这样达到了逻辑的复用~,哪里需要哪里调用就可以了。
    return postion;
};

export default function App() {
    const { x, y } = useMousePostion(); // 内部维护自己的postion相关的逻辑
    return (
        <div>
            current position x: {x}, y: {y}
        </div>
    );
}

Онлайн-демонстрация кода наздесь

Спасибо за исправление в области комментариев, я проверил исходный код реакции.Чтобы разобраться с совместимостью object.is, я использовалobjectIs

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

Конечно, правильно использовать хук реакции невозможно, и есть много статей с объяснением.Эта статья не слишком глубока, но это просто введение.Вот несколько хороших ресурсов для Amway:

начиная:

Глубоко:

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

Знакомство с vue-хуками

Видео, объясненное Ю Да, находится по адресуздесь

Поскольку vue3.0 еще не выпущен, мы все еще смотрим на демо-код, предоставленный Youda:

import { value, computed, watch, onMounted } from 'vue'

function useMouse() {
  const x = value(0)
  const y = value(0)
  const update = e => {
    x.value = e.pageX
    y.value = e.pageY
  }
  onMounted(() => {
    window.addEventListener('mousemove', update)
  })
  onUnmounted(() => {
    window.removeEventListener('mousemove', update)
  })
  return { x, y }
}

// 在组件中使用该函数
const Component = {
  setup() {
    const { x, y } = useMouse()
    // 与其它函数配合使用
    const { z } = useOtherLogic()
    return { x, y, z }
  },
  template: `<div>{{ x }} {{ y }} {{ z }}</div>`
}

Видно, что мы также можем выделить некоторую логику, которую нужно переиспользовать, в отдельную функцию useMouse, и тогда некоторое содержимое жизненного цикла и значения, определенное в этой функции, будет «подцеплено» вызовом функции setup. компонент, а данные, возвращаемые этой функцией, можно напрямую использовать в шаблоне, подождем появления 3.0 для более конкретного геймплея.

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

same & diff Point

Прочитав реализацию хуков в двух фреймворках, давайте проведем простое сравнение.

  1. Same Point:
  • Предыстория и проблема, которую нужно решить, одинаковы.Два фреймворка предназначены для решения некоторых проблем, таких как чрезмерное повторное использование логики и чрезмерный размер кода, включая эту проблему.Мы редко сталкиваемся с этим при использовании функций-функций.
  • Методы использования аналогичны: они извлекают некоторую отдельную логику, которую можно повторно использовать в отдельной функции, и возвращают данные, которые необходимо использовать в компоненте, и внутренне поддерживают обновление данных, тем самым запуская обновление представления.
  1. Diff Point:

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

function App(){
    const [name, setName] = useState('demo');
    if(condition){
        const [val, setVal] = useState('');
    }
}

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

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

Конечно, у React есть решения для этих проблем.Студенты, которые хотят узнать больше, могут перейти на официальный сайт для ознакомления, например, о роли хуков, таких как useCallback и useMemo.Давайте взглянем на резюме Youda и сравним хуки vue и react. :

1. Это больше соответствует интуиции JavaScript в целом;

2. Не ограничено последовательностью вызова и может вызываться условно;

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

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

5. Не беспокойтесь о передаче неправильного массива зависимостей в useEffect/useMemo/useCallback и использовании значений с истекшим сроком действия в обратном вызове — отслеживание зависимостей Vue полностью автоматическое.

Я должен сказать, что синий лучше, чем синий.Хотя Vue опирается на реакцию, его естественные адаптивные данные прекрасно избегают некоторых недостатков, с которыми сталкиваются реагирующие крючки ~

Суммировать

  1. Функциональный компонент станет направлением для разработки основных фреймворков в будущем, и естественное удобство функций для TS также оказывает важное влияние;
  2. Начальная стоимость хука реакции будет выше, чем у vue, и vue, естественно, позволяет избежать некоторых из более сложных частей реакции;
  3. Хук должен быть трендом в большом фронтенде, и сейчас это только начальная стадия:SwiftUI-Hooks, flutter_hooks...

Поскольку исходный код vue3.0 еще не выпущен, многие реализации являются догадками. Добро пожаловать, чтобы задавать вопросы и обсуждать вместе!

Если вы найдете это полезным, пожалуйста, поставьте лайк, спасибо, ваш лайк - моя постоянная мотивация~