후크는 어떻습니까? vue와 React가 모두 후크를 선택하는 이유는 무엇입니까?

青灯夜游
풀어 주다: 2022-03-02 10:09:19
앞으로
2945명이 탐색했습니다.

이 글에서는 Hook에 대해 알아보고 vue와 React가 그것을 선택하는 이유, Hook이 필요한 이유, 그리고 Vue와 React Custom Hook의 유사점과 차이점에 대해 이야기해 보겠습니다. 모두에게 도움이 되기를 바랍니다!

후크는 어떻습니까? vue와 React가 모두 후크를 선택하는 이유는 무엇입니까?

이 기사를 읽으면 다음과 같은 이점이 있습니다.

  • vuereact에서 Hooks의 현재 상황을 미리 이해하게 됩니다. >Hooksvuereact 的现状

  • 听一听本文作者关于 Hooks 的定义和总结

  • 弄懂“为什么我们需要 Hooks

  • 进行一些简单的 Hooks 实践

一、hooks: 什么叫大势所趋?

2019年年初,react16.8.x 版本正式具备了 hooks 能力。

2019年6月,尤雨溪在 vue/github-issues 里提出了关于 vue3 Component API 的提案。(vue hooks的基础)

在后续的 reactvue3 相关版本中,相关 hooks 能力都开始被更多人所接受。【相关推荐:vuejs视频教程

除此之外,solid.jspreact 等框架,也是开始选择加入 hooks 大家庭。

후크는 어떻습니까? vue와 React가 모두 후크를 선택하는 이유는 무엇입니까?

可以预见,虽然目前仍然是 class Componenthooks api 并驾齐驱的场面,但未来几年里,hooks 极有可能取代 class Component 成为业内真正的主流。

二、什么是 hooks

年轻时你不懂我,就像后来我不懂 hooks

2.1 hooks 的定义

"hooks" 直译是 “钩子”,它并不仅是 react,甚至不仅是前端界的专用术语,而是整个行业所熟知的用语。通常指:

系统运行到某一时期时,会调用被注册到该时机的回调函数。

比较常见的钩子有:windows 系统的钩子能监听到系统的各种事件,浏览器提供的 onloadaddEventListener 能注册在浏览器各种时机被调用的方法。

以上这些,都可以被称一声 "hook"。

但是很显然,在特定领域的特定话题下,hooks 这个词被赋予了一些特殊的含义。

react@16.x 之前,当我们谈论 hooks 时,我们可能谈论的是“组件的生命周期”。

但是现在,hooks 则有了全新的含义。

react 为例,hooks 是:

一系列以 “use” 作为开头的方法,它们提供了让你可以完全避开 class式写法,在函数式组件中完成生命周期、状态管理、逻辑复用等几乎全部组件开发工作的能力。

简化一下:

一系列方法,提供了在函数式组件中完成开发工作的能力。

(记住这个关键词: 函数式组件

import { useState, useEffect, useCallback } from 'react';
// 比如以上这几个方法,就是最为典型的 Hooks
로그인 후 복사

而在 vue 中, hooks 的定义可能更模糊,姑且总结一下:

vue 组合式API里,以 “use” 作为开头的,一系列提供了组件复用、状态管理等开发能力的方法。

(关键词:组合式API

import { useSlots, useAttrs } from 'vue';
import { useRouter } from 'vue-router';
// 以上这些方法,也是 vue3 中相关的 Hook!
로그인 후 복사

如:useSlotsuseAttrsuseRouter 等。

但主观来说,我认为vue 组合式API其本身就是“vue hooks”的关键一环,起到了 react hooks里对生命周期、状态管理的核心作用。(如 onMountedref 等等)。

후크는 어떻습니까? vue와 React가 모두 후크를 선택하는 이유는 무엇입니까?

如果按这个标准来看的话,vuereacthooks 的定义,似乎都差不多。

那么为什么要提到是以 “use” 作为开头的方法呢?

2.2 命名规范 和 指导思想

通常来说,hooks 的命名都是以 use 作为开头,这个规范也包括了那么我们自定义的 hooks

이 기사의 저자가 후크를 정의하고 요약한 내용을 들어보세요

🎜🎜"후크가 필요한 이유"를 이해하세요🎜 🎜🎜몇 가지 간단한 후크 사례 진행🎜

1. 후크: 일반적인 추세는 무엇입니까? 🎜🎜2019년 초, react16.8.x 버전에서 공식적으로 hooks 기능을 갖췄습니다. 🎜🎜2019년 6월, You Yuxi는 vue/github-issues🎜에서 vue3 Component API에 대한 제안이 작성되었습니다. (vue Hooks의 기본) 🎜🎜 reactvue3의 후속 버전에서는 관련 hooks 기능이 더 많은 사람들에게 수용되기 시작했습니다. [관련 권장 사항: vuejs 비디오 튜토리얼🎜]🎜🎜이 외에도 또한 solid.jspreact와 같은 프레임워크도 hooks 제품군에 합류하기 시작했습니다. 🎜🎜후크는 어떻습니까? vue와 React가 모두 후크를 선택하는 이유는 무엇입니까?🎜🎜예 class Componenthooks api가 여전히 나란히 경쟁하고 있지만 향후 몇 년 내에 hooks가 대체할 가능성이 매우 높을 것으로 예상됩니다. class Component는 업계의 진정한 주류가 되었습니다. 🎜

2. 후크란 무엇인가요? 🎜
🎜나중에 내가 을 이해하지 못한 것처럼 당신도 어렸을 때 나를 이해하지 못했습니다. 🎜

2.1 후크의 정의

🎜"후크"는 문자 그대로 "후크"로 번역되며 단순한 가 아닙니다. React 는 프론트엔드 세계의 특별한 용어일 뿐만 아니라 업계 전체에서 잘 알려진 용어입니다. 일반적으로 다음을 의미합니다. 🎜
🎜시스템이 특정 기간까지 실행되면 해당 시간에 등록된 콜백 함수가 호출됩니다. 🎜
🎜더 일반적인 후크는 다음과 같습니다: windows 시스템 후크는 시스템의 다양한 이벤트를 모니터링할 수 있습니다. 브라우저는 onload 또는 addEventListener를 제공합니다. 브라우저에서 다양한 시점에 호출될 메소드를 등록할 수 있습니다. 🎜🎜위의 내용은 모두 "훅"이라고 할 수 있습니다. 🎜🎜그러나 분명히 특정 분야의 특정 주제에서 후크라는 단어에는 특별한 의미가 부여되었습니다. 🎜🎜react@16.x 이전에 후크에 대해 이야기할 때 우리는 아마도 "구성 요소 수명 주기"에 대해 이야기했을 것입니다. 🎜🎜하지만 이제 후크는 완전히 새로운 의미를 갖습니다. 🎜🎜 react를 예로 들면 hooks는 🎜
🎜It를 제공하는 "use"로 시작하는 일련의 메서드입니다. 클래스 스타일 작성을 완전히 피하고 기능 구성 요소의 수명 주기, 상태 관리, 논리 재사용 등 거의 모든 구성 요소 개발 작업을 완료할 수 있습니다. 🎜
🎜단순화: 🎜
🎜일련의 방법을 사용하면 기능 구성 요소에서 개발 작업을 완료할 수 있습니다. 🎜
🎜 (이 키워드를 기억하세요: 기능적 구성 요소) 🎜
// 混入文件:name-mixin.js
export default {
  data() {
    return {
      name: genRandomName() // 假装它能生成随机的名字
    }
  },
  methods: {
    setName(name) {
      this.name = name
    }
  }
}
로그인 후 복사
로그인 후 복사
🎜그리고 vue에서는 hooks 정의가 가능합니다. 모호하지만 요약하자면: 🎜
🎜vue 통합 API에서는 “use”로 시작하여 재사용 및 상태 관리 및 상태 관리를 위한 일련의 구성 요소가 제공됩니다. 능력을 개발하는 다른 방법. 🎜
🎜 (키워드: 결합된 API) 🎜
// 组件:my-component.vue
<template>
  <div>{{ name }}</div>
<template>
<script>
import nameMixin from &#39;./name-mixin&#39;;
export default {
  mixins: [nameMixin],
  // 通过mixins, 你可以直接获得 nameMixin 中所定义的状态、方法、生命周期中的事件等
  mounted() {
    setTimeout(() => {
      this.setName(&#39;Tom&#39;)
    }, 3000)
  }
}
<script>
로그인 후 복사
로그인 후 복사
🎜 예: useSlots, useAttrs, useRouter</code 코드> 등 🎜🎜하지만 주관적으로는 <code>vue 결합 API 자체가 react Hooks 코어에서 수명주기 및 상태 관리 역할을 하는 "vue Hooks"의 핵심 부분이라고 생각합니다. 역할. (예: onMounted, ref 등) 🎜🎜후크는 어떻습니까? vue와 React가 모두 후크를 선택하는 이유는 무엇입니까?🎜🎜If 이 표준에 따르면 vuereacthooks 정의는 유사한 것으로 보입니다. 🎜🎜그럼 “use”로 시작하는 메소드를 언급하는 이유는 무엇인가요? 🎜

2.2 명명 사양 및 지침 이데올로기

🎜일반적으로 후크는 처음에 use로 명명됩니다. , 이 사양에는 사용자 정의 후크도 포함되어 있습니다. 🎜🎜왜? 🎜

因为(爱情 误)约定。

react 官方文档里,对 hooks 的定义和使用提出了 “一个假设、两个只在” 核心指导思想。(播音腔)

후크는 어떻습니까? vue와 React가 모두 후크를 선택하는 이유는 무엇입니까?

一个假设: 假设任何以 「use」 开头并紧跟着一个大写字母的函数就是一个 Hook

第一个只在: 只在 React 函数组件中调用 Hook,而不在普通函数中调用 Hook。(Eslint 通过判断一个方法是不是大坨峰命名来判断它是否是 React 函数)

第二个只在: 只在最顶层使用 Hook,而不要在循环,条件或嵌套函数中调用 Hook。

因为是约定,因而 useXxx 的命名并非强制,你依然可以将你自定义的 hook 命名为 byXxx 或其他方式,但不推荐。

因为约定的力量在于:我们不用细看实现,也能通过命名来了解一个它是什么。

以上 “一个假设、两个只在” 总结自 react 官网:

  • https://zh-hans.reactjs.org/docs/hooks-rules.html

  • https://zh-hans.reactjs.org/docs/hooks-faq.html#what-exactly-do-the-lint-rules-enforce

三、为什么我们需要 hooks ?

3.1 更好的状态复用

怼的就是你,mixin

class 组件模式下,状态逻辑的复用是一件困难的事情。

假设有如下需求:

当组件实例创建时,需要创建一个 state 属性:name,并随机给此 name 属性附一个初始值。除此之外,还得提供一个 setName 方法。你可以在组件其他地方开销和修改此状态属性。

更重要的是: 这个逻辑要可以复用,在各种业务组件里复用这个逻辑。

在拥有 Hooks 之前,我首先会想到的解决方案一定是 mixin

代码如下:(此示例采用 vue2 mixin 写法 )

// 混入文件:name-mixin.js
export default {
  data() {
    return {
      name: genRandomName() // 假装它能生成随机的名字
    }
  },
  methods: {
    setName(name) {
      this.name = name
    }
  }
}
로그인 후 복사
로그인 후 복사
// 组件:my-component.vue
<template>
  <div>{{ name }}</div>
<template>
<script>
import nameMixin from &#39;./name-mixin&#39;;
export default {
  mixins: [nameMixin],
  // 通过mixins, 你可以直接获得 nameMixin 中所定义的状态、方法、生命周期中的事件等
  mounted() {
    setTimeout(() => {
      this.setName(&#39;Tom&#39;)
    }, 3000)
  }
}
<script>
로그인 후 복사
로그인 후 복사

粗略看来,mixins 似乎提供了非常不错的复用能力,但是,react官方文档直接表明:

후크는 어떻습니까? vue와 React가 모두 후크를 선택하는 이유는 무엇입니까?

为什么呢?

因为 mixins 虽然提供了这种状态复用的能力,但它的弊端实在太多了

弊端一:难以追溯的方法与属性!

试想一下,如果出现这种代码,你是否会怀疑人生:

export default {
  mixins: [ a, b, c, d, e, f, g ], // 当然,这只是表示它混入了很多能力
  mounted() {
    console.log(this.name)
    // mmp!这个 this.name 来自于谁?我难道要一个个混入看实现?
  }
}
로그인 후 복사

又或者:

a.js mixins: [b.js]

b.js mixins: [c.js]

c.js mixins: [d.js]

// 你猜猜看, this.name 来自于谁?
// 求求你别再说了,我血压已经上来了
로그인 후 복사

弊端二:覆盖、同名?贵圈真乱!

当我同时想混入 mixin-a.jsmixin-b.js 以同时获得它们能力的时候,不幸的事情发生了:

由于这两个 mixin 功能的开发者惺惺相惜,它们都定义了 this.name 作为属性。

这种时候,你会深深怀疑,mixins 究竟是不是一种科学的复用方式。

弊端三:梅开二度?代价很大!

仍然说上面的例子,如果我的需求发生了改变,我需要的不再是一个简单的状态 name,而是分别需要 firstNamelastName
此时 name-mixin.js 混入的能力就会非常尴尬,因为我无法两次 mixins 同一个文件。

当然,也是有解决方案的,如:

// 动态生成mixin
function genNameMixin(key, funcKey) {
  return {
    data() {
      return {
        [key]: genRandomName()
      }
    },
    methods: {
      [funcKey]: function(v) {
        this.[key] = v
      } 
    }
  }
}

export default {
  mixins: [
    genNameMixin(&#39;firstName&#39;, &#39;setFirstName&#39;),
    genNameMixin(&#39;lastName&#39;, &#39;setLastName&#39;),
  ]
}
로그인 후 복사

确实通过动态生成 mixin 完成了能力的复用,但这样一来,无疑更加地增大了程序的复杂性,降低了可读性。

因此,一种新的 “状态逻辑复用” 就变得极为迫切了——它就是 Hooks!

Hook 的状态复用写法:

// 单个name的写法
const { name, setName } = useName();

// 梅开二度的写法
const { name : firstName, setName : setFirstName } = useName();

const { name : secondName, setName : setSecondName } = useName();
로그인 후 복사

相比于 mixins,它们简直太棒了!

  1. 方法和属性好追溯吗?这可太好了,谁产生的,哪儿来的一目了然。
  2. 会有重名、覆盖问题吗?完全没有!内部的变量在闭包内,返回的变量支持定义别名。
  3. 多次使用,没开N度?你看上面的代码块内不就“梅开三度” 了吗?

就冲 “状态逻辑复用” 这个理由,Hooks 就已经香得我口水直流了。

3.2 代码组织

熵减,宇宙哲学到编码哲学。

项目、模块、页面、功能,如何高效而清晰地组织代码,这一个看似简单的命题就算写几本书也无法完全说清楚。

但一个页面中,N件事情的代码在一个组件内互相纠缠确实是在 Hooks 出现之前非常常见的一种状态。

那么 Hooks 写法在代码组织上究竟能带来怎样的提升呢?

후크는 어떻습니까? vue와 React가 모두 후크를 선택하는 이유는 무엇입니까?

(假设上图中每一种颜色就代码一种高度相关的业务逻辑)

无论是 vue 还是 react, 通过 Hooks 写法都能做到,将“分散在各种声明周期里的代码块”,通过 Hooks 的方式将相关的内容聚合到一起。

这样带来的好处是显而易见的:“高度聚合,可阅读性提升”。伴随而来的便是 “效率提升,bug变少”

按照“物理学”里的理论来说,这种代码组织方式,就算是“熵减”了。

3.3 比 <span style="font-size: 16px;">class</span> 组件更容易理解

尤其是 this

reactclass 写法中,随处可见各种各样的 .bind(this)。(甚至官方文档里也有专门的章节描述了“为什么绑定是必要的?”这一问题)

vue 玩家别笑,computed: { a: () => { this } } 里的 this 也是 undefined

很显然,绑定虽然“必要”,但并不是“优点”,反而是“故障高发”地段。

但在Hooks 写法中,你就完全不必担心 this 的问题了。

因为:

本来无一物,何处惹尘埃。

Hooks 写法直接告别了 this,从“函数”来,到“函数”去。

妈妈再也不用担心我忘记写 bind 了。

3.4 友好的渐进式

随风潜入夜,润物细无声。

渐进式的含义是:你可以一点点深入使用。

无论是 vue 还是 react,都只是提供了 Hooks API,并将它们的优劣利弊摆在了那里。并没有通过无法接受的 break change 来强迫你必须使用 Hooks 去改写之前的 class 组件。

你依然可以在项目里一边写 class 组件,一边写 Hooks 组件,在项目的演进和开发过程中,这是一件没有痛感,却悄无声息改变着一切的事情。

但是事情发展的趋势却很明显,越来越多的人加入了 Hooks组合式API 的大军。

四、如何开始玩 hooks

4.1 环境和版本

react 项目中, react 的版本需要高于 16.8.0

而在 vue 项目中, vue3.x 是最好的选择,但 vue2.6+ 配合 @vue/composition-api,也可以开始享受“组合式API”的快乐。

4.2 react 的 <span style="font-size: 16px;">Hooks</span> 写法

因为 react Hooks 仅支持“函数式”组件,因此需要创建一个函数式组件 my-component.js

// my-component.js
import { useState, useEffect } from &#39;React&#39;

export default () => {
  // 通过 useState 可以创建一个 状态属性 和一个赋值方法
  const [ name, setName ] = useState(&#39;&#39;)

  // 通过 useEffect 可以对副作用进行处理
  useEffect(() => {
    console.log(name)
  }, [ name ])

  // 通过 useMemo 能生成一个依赖 name 的变量 message
  const message = useMemo(() => {
    return `hello, my name is ${name}`
  }, [name])

  return <div>{ message }</div>
}
로그인 후 복사

细节可参考 react 官方网站:https://react.docschina.org/docs/hooks-intro.html

4.3 vue 的 <span style="font-size: 16px;">Hooks</span> 写法

vue 的 Hooks 写法依赖于 组合式API,因此本例采用 <script setup> 来写:

<template>
  <div>
    {{ message }}
  </div>
</template>
<script setup>
import { computed, ref } from &#39;vue&#39;
// 定义了一个 ref 对象
const name = ref(&#39;&#39;)
// 定义了一个依赖 name.value 的计算属性
const message = computed(() => {
  return `hello, my name is ${name.value}`
})
</script>
로그인 후 복사

很明显,vue 组合式API里完成 useStateuseMemo 相关工作的 API 并没有通过 useXxx 来命名,而是遵从了 Vue 一脉相承而来的 refcomputed

虽然不符合 react Hook 定义的 Hook 约定,但 vueapi 不按照 react 的约定好像也并没有什么不妥。

参考网址:https://v3.cn.vuejs.org/api/composition-api.html

五、开始第一个自定义 hook

除了官方提供的 Hooks Api, Hooks 的另外一个重要特质,就是可以自己进行“自定义 Hooks” 的定义,从而完成状态逻辑的复用。

开源社区也都有很多不错的基于 Hooks 的封装,比如 ahooks (ahooks.js.org/zh-CN/),又比如 vueuse(vueuse.org/)

我还专门写过一篇小文章介绍 vuehook:

  • 【一库】vueuse:我不许身为vuer,你的工具集只有lodash!。

  • https://juejin.cn/post/7030395303433863205

후크는 어떻습니까? vue와 React가 모두 후크를 선택하는 이유는 무엇입니까?

那么,我们应该怎么开始撰写 “自定义Hooks” 呢?往下看吧!

5.1 react 玩家看这里

react 官方网站就专门有一个章节讲述“自定义Hook”。(https://react.docschina.org/docs/hooks-custom.html)

这里,我们扔用文章开头那个 useName 的需求为例,希望达到效果:

const { name, setName } = useName();
// 随机生成一个状态属性 name,它有一个随机名作为初始值
// 并且提供了一个可随时更新该值的方法 setName
로그인 후 복사

如果我们要实现上面效果,我们该怎么写代码呢?

import React from &#39;react&#39;;

export const useName = () => {
  // 这个 useMemo 很关键
  const randomName = React.useMemo(() => genRandomName(), []);
  const [ name, setName ] = React.useState(randomName)

  return {
    name,
    setName
  }
}
로그인 후 복사

忍不住要再次感叹一次,和 mixins 相比,它不仅使用起来更棒,就连定义起来也那么简单。

可能有朋友会好奇,为什么不直接这样写:

const [ name, setName ] = React.useState(genRandomName())
로그인 후 복사

因为这样写是不对的,每次使用该 Hook 的函数组件被渲染一次时,genRandom() 方法就会被执行一次,虽然不影响 name 的值,但存在性能消耗,甚至产生其他 bug

为此,我写了一个能复现错误的demo,有兴趣的朋友可以点开验证:https://codesandbox.io/s/long-cherry-kzcbqr

2022-02-03日补充更正:经掘友提醒,可以通过 React.useState(() => randomName()) 传参来避免重复执行,这样就不需要 useMemo 了,感谢!

5.2 vue 玩家看这里

vue3 官网没有关于 自定义Hook 的玩法介绍,但实践起来也并不困难。

目标也定位实现一个 useName 方法:

import { ref } from &#39;vue&#39;;

export const useName = () => {
  const name = ref(genRandomName())
  const setName = (v) => {
    name.value = v
  }
  return {
    name,
    setName
  }
}
로그인 후 복사

5.3 <span style="font-size: 16px;">vue</span><span style="font-size: 16px;">react</span> 自定义 <span style="font-size: 16px;">Hook</span> 的异同

  • 相似点: 总体思路是一致的 都遵照着 "定义状态数据","操作状态数据","隐藏细节" 作为核心思路。

  • 差异点: 组合式APIReact函数组件 有着本质差异
    vue3 的组件里, setup 是作为一个早于 “created” 的生命周期存在的,无论如何,在一个组件的渲染过程中只会进入一次。
    React函数组件 则完全不同,如果没有被 memorized,它们可能会被不停地触发,不停地进入并执行方法,因此需要开销的心智相比于vue其实是更多的。

本文转载自:https://juejin.cn/post/7066951709678895141

作者:春哥的梦想是摸鱼

(学习视频分享:vuejs教程web前端

위 내용은 후크는 어떻습니까? vue와 React가 모두 후크를 선택하는 이유는 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:juejin.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿