iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > VUE >掌握Hooks的方法是什么
  • 321
分享到

掌握Hooks的方法是什么

2024-04-02 19:04:59 321人浏览 八月长安
摘要

这篇文章主要介绍“掌握Hooks的方法是什么”,在日常操作中,相信很多人在掌握Hooks的方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”掌握Hooks的方法是什么”

这篇文章主要介绍“掌握Hooks的方法是什么”,在日常操作中,相信很多人在掌握Hooks的方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”掌握Hooks的方法是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

在使用 React 开发的这段时间里,我最大的感受就是 “这是 React 最好的时代,也是最坏的时代” !「好」在于 hooks  开启了不一样的开发模式,在思考方式上要求更关注于数据之间的依赖关系,同时书写方式更加简便,总体上提升了开发效率;「坏」在于项目中经常是类组件与函数组件共存,而类组件以类编程思想为主导,开发过程中更关注于整个组件的渲染周期,在维护项目时常常需要在两种思维模式中左右横跳,这还不是最坏的一点。

某日,老王问我:“你一直在「每周一瞥」搬运 hooks 的文章,你觉得 hooks 有哪些易造成内存泄露的点?”  引发了我的深思(因为我的脑子一片空白)。我们一直在讨论 hooks,到底在讨论什么?虽然社区内关于 hooks 的讨论很多,但更多的是科普 Hooks api  怎么使用,亦或是将其与类组件生命周期、redux 进行对比,而缺少关于 hooks 最佳实践的讨论与共识,我想这才是「最坏」的一点。今天,我们不妨讨论一下  hooks 所带来的变化以及我们如何去拥抱这些变化。

注「每周一瞥」是团队内翻译并分享外网新鲜货的一个专栏。

掌握Hooks的方法是什么

React 16.8 发布以来,Hooks 深入人心,带来最大的变化有三点:思维模式的转变,渲染过程中作用域的变化以及数据流的改变。

思维模式

从 React 官网可以了解到,Hooks 的设计动机在于简化组件间状态逻辑的复用,支持开发者将关联的逻辑抽象为更小的函数,并降低认知成本,不用去理解  js Class 中令人窒息的 this。在这样的动机之下,hooks  中弱化了组件生命周期的概念,强化了状态与行为之间的依赖关系,这容易引导我们更多的关注“做什么”,而非“怎么做”[1]。

假设有这么一个场景:组件 Detail 中依赖父级组件传入的 query 参数进行数据请求,那么无论是基于类组件还是  Hooks,我们都需要定义一个异步请求方法  getData。不同的是,在类组件的开发模式中,我们要思考的更倾向于“怎么做”:在组件挂载完成时请求数据,并在组件发生更新时,比较新旧 query  值,必要时重新调用 getData 函数。

class Detail extends React.Component {   state = {     keyWord: '',   }    componentDidMount() {     this.getData();   }    getSnapshotBeforeUpdate(prevProps, prevState) {     if (this.props.query !== prevProps.query) {       return true;     }     return null;   }    componentDidUpdate(prevProps, prevState, snapshot) {     if (snapshot) {       this.getData();     }   }    async getData() {     // 这是一段异步请求数据的代码     console.log(`数据请求了,参数为:${this.props.query}`);     this.setState({       keyword: this.props.query     })   }    render() {     return (       <div>         <p>关键词: {this.state.keyword}</p>       </div>     );   } }

而在应用了 Hooks 的函数组件中,我们思考“做什么”:不同 query 值,展示不同的数据。

function Detail({   query }) {   const [keyword, seTKEyword] = useState('');    useEffect(() => {     const getData = async () => {       console.log(`数据请求了,参数为:${query}`);       setKeyword(query);     }      getData();   }, [query]);    return (     <div>       <p>关键词: {keyword}</p>     </div>   ); }

在这种主导下,开发者在编码过程中的思维模式也应随之改变,需要考虑数据与数据、数据与行为之间的同步关系。这种模式可以更简洁地将相关代码组合到一起,甚至抽象成自定义  hooks,实现逻辑的共享,似乎有了插拔式编程的味道。

虽然 Dan Abramov 在自己的博客中提到,从生命周期的角度思考并决定何时执行副作用是在逆势而为[2],但是了解各个 hooks  在组件渲染过程中的执行时机,有助于我们与 React 保持理解的一致性,能够更加准确地专注于“做什么”。 Donavon 以图表形式梳理对比了 hooks  范式与生命周期范式[3],能够帮助我们理解 hooks  在组件中的工作机制。每次组件发生更新时,都会重新调用组件函数,生成新的作用域,这种变化也对我们开发者提出了新的编码要求。

掌握Hooks的方法是什么

作用域

在类组件中,组件一旦实例化后,便有了自己的作用域,从创建到销毁,作用域始终不变。因此,在整个组件的生命周期中,每次渲染时内部变量始终指向同一个引用,我们可以很轻易的在每次渲染中通过  this.state 拿到最新的状态值,也可以使用 this.xx 获取到同一个内部变量。

class Timer extends React.Component {   state = {     count: 0,     interval: null,   }    componentDidMount() {     const interval = setInterval(() => {       this.setState({         count: this.state.count + 1,       })     }, 1000);      this.setState({       interval     });   }    componentDidUnMount() {     if (this.state.interval) {       clearInterval(this.state.interval);     }   }    render() {     return (       <div>         计数器为:{this.state.count}       </div>     );   } }

Hooks 中, render 与 state 的关系更像闭包与局部变量。每次渲染时,都会生成新的 state 变量,React  会向其写入当次渲染的状态值,并在当次渲染过程中保持不变。也即每次渲染互相独立,都有自己的状态值。同理,组件内的函数、定时器、副作用等也是独立的,内部所访问的也是当次渲染的状态值,因此常常会遇到定时器/订阅器内无法读取到最新值的情况。

function Timer() {   const [count, setCount] = useState(0);    useEffect(() => {     const interval = setInterval(() => {       setCount(count + 1);    // 始终只为 1      }, 1000);      return () => {       clearInterval(interval);     }   }, []);    return (     <div>       计数器为:{count}     </div>   ); }

如果我们想要拿到最新值,有两种解决方法:一是利用 setCount 的 lambada 形式,传入一个以上一次的状态值为参数的函数;二是借助 useRef  钩子,在其 current 属性中存储最新的值。

function Timer() {   const [count, setCount] = useState(0);    useEffect(() => {     const interval = setInterval(() => {       setCount(c => c + 1);     }, 1000);      return () => {       clearInterval(interval);     }   }, []);    return (     <div>       计数器为:{count}     </div>   ); }

在 hook-flow  的图中,我们可以了解到当父组件发生重新渲染时,其所有(状态、局部变量等)都是新的。一旦子组件依赖于父组件的某一个对象变量,那么无论对象是否发生变化,子组件拿到的都是新的对象,从而使子组件对应的  diff 失效,依旧会重新执行该部分逻辑。在下面的例子中,我们的副作用依赖项中包含了父组件传入的对象参数,每次父组件发生更新时,都会触发数据请求。

function Info({   style, }) {   console.log('Info 发生渲染');    useEffect(() => {     console.log('重新加载数据'); // 每次发生重新渲染时,都会重新加载数据   }, [style]);    return (     <p style={style}>       这是 Info 里的文字     </p>   ); }  function Page() {   console.log('Page 发生渲染');    const [count, setCount] = useState(0);   const style = { color: 'red' };    // 计数器 +1 时,引发 Page 的重新渲染,进而引发 Info 的重新渲染   return (     <div>       <h5>计数值为:{count}</h5>       <button onClick={() => setCount(count + 1)}> +1 </button>       <Info style={style} />     </div>   ); }

React Hooks 给我们提供了解决方案,useMemo 允许我们缓存传入的对象,仅当依赖项发生变化时,才重新计算并更新相应的对象。

function Page() {   console.log('Page 发生渲染');    const [color] = useState('red');   const [count, setCount] = useState(0);   const style = useMemo(() => ({ color }), [color]); // 只有 color 发生实质性改变时,style 才会变化    // 计数器 +1 时,引发 Page 的重新渲染,进而引发 Info 的重新渲染   // 但是由于 style 缓存了,因此不会触发 Info 内的数据重新加载   return (     <div>       <h5>计数值为:{count}</h5>       <button onClick={() => setCount(count + 1)}> +1 </button>       <Info style={style} />     </div>   ); }

数据流

React Hooks 在数据流上带来的变化有两点:一是支持更友好的使用 context  进行状态管理,避免层级过多时向中间层承载无关参数;二是允许函数参与到数据流中,避免向下层组件传入多余的参数。

useContext 作为 hooks 的核心模块之一,可以获取到传入 context 的当前值,以此达到跨层通信的目的。React  官网有着详细的介绍,需要关注的是一旦 context 值发生改变,所有使用了该 context 的组件都会重新渲染。为了避免无关的组件重绘,我们需要合理的构建  context ,比如从第一节提到的新思维模式出发,按状态的相关度组织 context,将相关状态存储在同一个 context 中。

在过去,如果父子组件用到同一个数据请求方法 getData ,而该方法又依赖于上层传入的 query 值时,通常需要将 query 和 getData  方法一起传递给子组件,子组件通过判断 query 值来决定是否重新执行 getData。

class Parent extends React.Component {    state = {     query: 'keyword',   }    getData() {     const url = `https://mocks.alibaba-inc.com/mock/fO87jdfKqX/demo/queryData.JSON?query=${this.state.query}`;     // 请求数据...     console.log(`请求路径为:${url}`);   }    render() {     return (       // 传递了一个子组件不渲染的 query 值       <Child getData={this.getData} query={this.state.query} />     );   } }  class Child extends React.Component {   componentDidMount() {     this.props.getData();   }    componentDidUpdate(prevProps) {     // if (prevProps.getData !== this.props.getData) { // 该条件始终为 true     //   this.props.getData();     // }     if (prevProps.query !== this.props.query) { // 只能借助 query 值来做判断       this.props.getData();     }   }    render() {     return (       // ...     );   } }

在 React Hooks 中 useCallback 支持我们缓存某一函数,当且仅当依赖项发生变化时,才更新该函数。这使得我们可以在子组件中配合  useEffect ,实现按需加载。通过 hooks 的配合,使得函数不再仅仅是一个方法,而是可以作为一个值参与到应用的数据流中。

function Parent() {   const [count, setCount] = useState(0);   const [query, setQuery] = useState('keyword');    const getData = useCallback(() => {     const url = `Https://mocks.alibaba-inc.com/mock/fO87jdfKqX/demo/queryData.json?query=${query}`;     // 请求数据...     console.log(`请求路径为:${url}`);   }, [query]);  // 当且仅当 query 改变时 getData 才更新    // 计数值的变化并不会引起 Child 重新请求数据   return (     <>       <h5>计数值为:{count}</h5>       <button onClick={() => setCount(count + 1)}> +1 </button>       <input onChange={(e) => {setQuery(e.target.value)}} />       <Child getData={getData} />     </>   ); }  function Child({   getData }) {   useEffect(() => {     getData();   }, [getData]);    // 函数可以作为依赖项参与到数据流中    return (     // ...   ); }

总结

回到最初的问题:“ hooks 有哪些易造成内存泄露的点?”,我理解造成内存泄露风险的在于 hooks  所带来的作用域的变化。由于每次渲染都是独立的,一旦有副作用引用了局部变量,并且未在组件销毁时及时释放,那么就极易造成内存泄露。关于如何更好的使用 hooks,  Sandro Dolidze 在博客中列了一个 checkList[4],我觉得是个不错的建议,可以帮助我们写出正确的 hooks 应用。

  1. 遵循 Hooks 规则;

  2. 不要在函数体中使用任何副作用,而是将其放到 useEffect 中执行;

  3. 取消订阅/处理/销毁所有已使用的资源;

  4. 首选 useReducer 或 useState 的函数更新,以防止在钩子中读写相同的值;

  5. 不要在 render 函数中使用可变变量,而是使用 useRef;

  6. 如果在 useRef 中保存的内容的生命周期比组件本身小,那么在处理资源时不要释放该值;

  7. 小心死循环和内存泄露;

  8. 当需要提高性能是,可以 memoize 函数和对象;

  9. 正确设置依赖项(undefined => 每次渲染; [a, b] => 当 a 或 b 改变时;[] => 仅执行一次);

  10. 在可复用用例中使用自定义 hooks.

到此,关于“掌握Hooks的方法是什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: 掌握Hooks的方法是什么

本文链接: https://www.lsjlt.com/news/84245.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 掌握Hooks的方法是什么
    这篇文章主要介绍“掌握Hooks的方法是什么”,在日常操作中,相信很多人在掌握Hooks的方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”掌握Hooks的方法是什么”...
    99+
    2024-04-02
  • 一文带你掌握掌握Golang结构体与方法
    目录1. Golang 结构体的概念及定义2. Golang 结构体的实例化2.1 new 函数2.2 var 关键字2.3 构造函数3. Golang 结构体的内嵌与组合3.1 结...
    99+
    2023-05-17
    Golang结构体与方法 Golang结构体 Golang 方法
  • PHP程序员必须掌握的编程算法是什么?
    编程算法是计算机科学中的重要部分,它们能够帮助程序员解决一系列的问题。对于PHP程序员来说,掌握一些基本的编程算法是非常必要的,因为这些算法可以帮助他们更有效地解决问题,提高编程效率。接下来,我们将介绍一些PHP程序员必须掌握的编程算法。...
    99+
    2023-08-12
    编程算法 spring 并发
  • MySQL死锁是什么及怎么掌握
    这篇“MySQL死锁是什么及怎么掌握”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“MySQ...
    99+
    2024-04-02
  • React中Hooks是什么
    这篇文章给大家分享的是有关React中Hooks是什么的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。什么是 HooksHooks 译为钩子,Hooks 就是在函数组件内,负责钩进...
    99+
    2024-04-02
  • React Hooks的原理是什么
    这篇文章主要讲解了“React Hooks的原理是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“React Hooks的原理是什么”吧!0x0...
    99+
    2024-04-02
  • 一文掌握new Date() 方法
    目录可恶的四宗罪1. Safari浏览器不兼容YYYY-MM-DD这样的格式2、月份的索引是以0为起点的,而年份、日期却不是3、年份小于100,默认以19xx或20xx开头4、日期初...
    99+
    2023-05-16
    new Date() 方法 js new Date()
  • 快速掌握CSS框架的方法
    简明易懂:CSS框架如何快速上手,需要具体代码示例 简介:CSS框架是前端开发中常用的工具,它可以帮助我们快速构建美观且响应式的网页。然而,对于初学者来说,学习并使用CSS框架可能会有一定的困难。本篇文章将简要介绍CSS框架的基...
    99+
    2024-01-16
    快速上手 CSS框架
  • 快速掌握VueRouter使用方法
    目录一、编程式路由导航二、缓存路由组件三、两个新的声明周期钩子四、路由守卫五、路由器的两种工作模式本篇博客会介绍Vue中的VueRouter的基本使用,编程式路由导航增加了我们进行路...
    99+
    2023-01-09
    Vue Router用法 Vue Router原理
  • Java快速掌握Vector类方法
    目录Vector的基本介绍Vector类支持4种构造方法一些常用的方法1.add方法2.remove方法3.set方法4.size、capacity、get方法代码Vector的基本...
    99+
    2024-04-02
  • react hooks组件间的传值方式是什么
    这篇文章给大家介绍react hooks组件间的传值方式是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。父传子通过props传值,使用useState来控制state的状态值父组件 Father.tsx里:子组件 ...
    99+
    2023-06-25
  • 快速掌握Fedora 17的方法详解
    要快速掌握Fedora 17,可以按照以下步骤进行:1. 下载和安装Fedora 17:首先,您需要从官方网站上下载Fedora 1...
    99+
    2023-09-23
    Fedora
  • hooks的实现原理是什么
    Hooks是React 16.8版本引入的一种新特性,它可以让我们在不编写class的情况下使用state和其他React的特性。H...
    99+
    2023-10-10
    hooks
  • 掌握Go语言create方法的常见用法
    【标题】掌握Go语言create方法的常见用法 Go语言是一种简洁、高效的编程语言,受到越来越多程序员的喜爱。在Go语言中,很多数据类型都包含了create方法,用于创建新的实例对象。...
    99+
    2024-03-12
    go语言 create方法 常见用法 键值对
  • JavaScript ES6值得掌握的五大功能是什么
    这篇文章主要介绍“JavaScript ES6值得掌握的五大功能是什么”,在日常操作中,相信很多人在JavaScript ES6值得掌握的五大功能是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操...
    99+
    2024-04-02
  • Vue3通过ref操作Dom元素及hooks的使用方法是什么
    这篇文章主要介绍了Vue3通过ref操作Dom元素及hooks的使用方法是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Vue3通过ref操作Dom元素及hooks的使用方法是什么文章都会有所收获,下面我们...
    99+
    2023-07-05
  • Java开发技术:掌握容器编程算法的关键是什么?
    在Java开发中,容器是一个非常重要的概念。Java中的容器可以理解为一种数据结构,用于存储和管理一组对象。在Java中,常见的容器有List、Set、Map等。掌握容器编程算法是Java开发的必备技能之一,因为它能够帮助我们更好地管理和...
    99+
    2023-08-08
    容器 编程算法 开发技术
  • Vue2 diff算法怎么掌握
    今天小编给大家分享一下Vue2 diff算法怎么掌握的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。什么是 diff 在我的理...
    99+
    2023-07-05
  • Web开发必须掌握的三个技术是什么
    这篇文章主要介绍“Web开发必须掌握的三个技术是什么”,在日常操作中,相信很多人在Web开发必须掌握的三个技术是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Web开发必...
    99+
    2024-04-02
  • Laravel 初学者必须掌握的 Python 技能是什么?
    Laravel 是一个广受欢迎的 PHP 框架,它的高效性和易用性使得它成为了许多 PHP 开发者的首选。然而,随着人工智能和大数据时代的到来,Python 已经成为了许多开发者的新宠,而且 Python 在数据处理和人工智能方面的表现尤为...
    99+
    2023-08-02
    学习笔记 laravel bash
软考高级职称资格查询
推荐阅读
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作