前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >React hooks实践

React hooks实践

作者头像
嘿嘿嘿
发布于 2019-02-26 01:57:15
发布于 2019-02-26 01:57:15
1.4K00
代码可运行
举报
文章被收录于专栏:陈纪庚陈纪庚
运行总次数:0
代码可运行

前言

最近要对旧的项目进行重构,统一使用全新的react技术栈。同时,我们也决定尝试使用React hooks来进行开发,但是,由于React hooks崇尚的是使用(也只能使用)function component的形式来进行开发,而不是class component,因此,整个开发方式也会与之前产生比较大的差异。所以,我这里就积累了下实际项目中遇到的问题以及思考,看下能不能帮助大家少走弯路。

正文

接下来就直接进入正文。我会将项目中遇到的问题一一列举出来,并且给出解决方案。

执行初始化操作的时机

当我转到React hooks的时候,首先就遇到了这个问题:

一般来说,业务组件经常会遇到要通过发起ajax请求来获取业务数据并且执行初始化操作的场景。在使用class component编程的时候,我们就可以在class component提供的生命周期钩子函数(比如componentDidMount, constructor等)执行这个操作。可是如果转到React hooks之后,function component里是没有这个生命周期钩子函数的,那这个初始化操作怎么办呢?总不能每次遇到这种场景都使用class component来做吧?

解决方案:使用useEffect(想知道useEffect是什么的话,可以点击这里)

useEffect,顾名思义,就是执行有副作用的操作,你可以把它当成componentDidMount, componentDidUpdate, and componentWillUnmount 的集合。它的函数声明如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
useEffect(effect: React.EffectCallback, inputs?: ReadonlyArray<any> | undefined)

那么,我们在实际使用中,我们就可以使用这个来执行初始化操作。举个例子

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React, { useEffect } from 'react'

export function BusinessComponent() {
  const initData = async () => {
    // 发起请求并执行初始化操作
  }
  // 执行初始化操作,需要注意的是,如果你只是想在渲染的时候初始化一次数据,那么第二个参数必须传空数组。
  useEffect(() => {
    initData();
  }, []);

  return (<div></div>);
}

需要注意的是,这里的useEffect的第二个参数必须传空数组,这样它就等价于只在componentDidMount的时候执行。如果不传第二个参数的话,它就等价于componentDidMount和componentDidUpdate

做一些清理操作

由于我们在实际开发过程中,经常会遇到需要做一些副作用的场景,比如轮询操作(定时器、轮询请求等)、使用浏览器原生的事件监听机制而不用react的事件机制(这种情况下,组件销毁的时候,需要用户主动去取消事件监听)等。使用class Component编程的时候,我们一般都在componentWillUnmount或者componentDidUnmount的时候去做清理操作,可是使用react hooks的时候,我们如何做处理呢?

解决方案:使用useEffect第一个参数的返回值

如果useEffect的第一个参数返回了函数的时候,react会在每一次执行新的effects之前,执行这个函数来做一些清理操作。因此,我们就可以使用它来执行一些清理操作。

例子:比如我们要做一个二维码组件,我们需要根据传入的userId不断轮询地向后台发请求查询扫描二维码的状态,这种情况下,我们就需要在组件unmount的时候清理掉轮询操作。代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React, { useEffect } from 'react'

export function QRCode(url, userId) {
  // 根据userId查询扫描状态
  const pollingQueryingStatus = async () => {
  }
  // 取消轮询
  const stopPollingQueryStatus = async() => {
  }

  useEffect(() => {
    pollingQueryingStatus();

    return stopPollingQueryStatus;
  }, []);

  // 根据url生成二维码
  return (<div></div>)
}

这样的话,就等价于在componentWillUnmount的时候去执行清理操作。

但是,有时候我们可能需要执行多次清理操作。还是举上面的例子,我们需要在用户传入新的userId的时候,去执行新的查询的操作,同时我们还需要清除掉旧的轮询操作。想一下怎么做比较好。

其实对这种情况,官方也已经给出了解决方案了,useEffect的第二个参数是触发effects的关键,如果用户传入了第二个参数,那么只有在第二个参数的值发生变化(以及首次渲染)的时候,才会触发effects。因此,我们只需要将上面的代码改一下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React, { useEffect } from 'react'

export function QRCode(url, userId) {
  // 根据userId查询扫描状态
  const pollingQueryingStatus = async () => {
  }

  const stopPollingQueryStatus = async() => {
  }
  // 我们只是将useEffect的第二个参数加了个userId
  useEffect(() => {
    pollingQueryingStatus();

    return stopPollingQueryStatus;
  }, [userId]);

  // 根据url生成二维码
  return (<div></div>)
}

我们只是在useEffect的第二个参数数组里,加入了一个userId。这样的话,userId的每一次变化都会先触发stopPollingQueryStatus,之后再执行effects,这样就可以达到我们的目的。

useState与setState的差异

react hooks使用useState来代替class Component里的state。可是,在具体开发过程中,我也发现了一些不同点。useState介绍可以点击这里

在setState的时候,我们可以只修改state中的局部变量,而不需要将整个修改后的state传进去,举个例子

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React, { PureComponent } from 'react';

export class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
      name: 'cjg',
      age: 18,
    }
  }

  handleClick = () => {
    const { count } = this.state;
    // 我们只需要传入修改的局部变量
    this.setState({
      count: count + 1,
    });
  }

  render() {
    return (
      <button onClick={this.handleClick}></button>
    )
  }
}

而使用useState后,我们修改state必须将整个修改后的state传入去,因为它会直接覆盖之前的state,而不是合并之前state对象。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React, { useState } from 'react';

export function Count() {
  const [data, setData] = useState({
    count: 0,
    name: 'cjg',
    age: 18,
  });
    
  const handleClick = () => {
    const { count } = data;
    // 这里必须将完整的state对象传进去
    setData({
      ...data,
      count: count + 1,
    })
  };

  return (<button onClick={handleClick}></button>)
}

减少不必要的渲染

在使用class Component进行开发的时候,我们可以使用shouldComponentUpdate来减少不必要的渲染,那么在使用react hooks后,我们如何实现这样的功能呢?

解决方案:React.memouseMemo

对于这种情况,react当然也给出了官方的解决方案,就是使用React.memo和useMemo。

React.memo

React.momo其实并不是一个hook,它其实等价于PureComponent,但是它只会对比props。使用方式如下(用上面的例子):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React, { useState } from 'react';

export const Count = React.memo((props) => {
  const [data, setData] = useState({
    count: 0,
    name: 'cjg',
    age: 18,
  });
  
  const handleClick = () => {
    const { count } = data;
    setData({
      ...data,
      count: count + 1,
    })
  };

  return (<button onClick={handleClick}>count:{data.count}</button>)
});
useMemo

useMemo它的用法其实跟useEffects有点像,我们直接看官方给的例子

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function Parent({ a, b }) {
  // Only re-rendered if `a` changes:
  const child1 = useMemo(() => <Child1 a={a} />, [a]);
  // Only re-rendered if `b` changes:
  const child2 = useMemo(() => <Child2 b={b} />, [b]);
  return (
    <>
      {child1}
      {child2}
    </>
  )
}

从例子可以看出来,它的第二个参数和useEffect的第二个参数是一样的,只有在第二个参数数组的值发生变化时,才会触发子组件的更新。

总结

一开始在从class component转变到react hooks的时候,确实很不适应。可是当我习惯了这种写法后,我的心情如下:

当然,现在react hooks还是在alpha阶段,如果大家觉得不放心的话,可以再等等。反正我就先下手玩玩了哈哈哈。

本文地址在->本人博客地址, 欢迎给个 start 或 follow

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-01-27 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Spring Boot与事务钩子函数:概念与实战
在复杂的业务逻辑中,事务管理是确保数据一致性和完整性的关键。Spring Boot提供了强大的事务管理机制,其中事务钩子函数(Transaction Hooks)允许开发者在事务的不同阶段插入自定义逻辑。本篇博客将详细探讨事务钩子函数的概念及其在Spring Boot中的应用。
小马哥学JAVA
2024/04/30
5270
一分钟知识点:钩子函数
的作用是往jvm中添加一个钩子,当jvm关闭的时候(程序退出),jvm会调用所有注册的钩子函数。钩子函数启动一个独立的线程,一般用来做资源的关闭和清理。
用户7634691
2020/08/10
4430
VUE钩子函数
张哥编程
2024/12/19
1000
VUE钩子函数
Android开发之模板模式初探
模板模式我认为在Android的开发中是最长用到的,基本是随处可见的,认识该模式,有助于我们对Android的源代码及框架有一个更深层次的认识。那什么是模板模式呢,模板模式就是定义一个基本框架,将当中的一些方法延迟到子类中运行实现。就比方我们去餐馆吃饭,基本步骤肯定为找到座位,点菜,上菜,吃饭,买单五个过程,当中点菜这个过程是可变的,我们点的菜可多可少,其它都是固定的,那么我们就能够写在一个固定的抽象类里形成一个基本框架,我们的子类继承该抽象类,对当中可变的方法进行复写。
全栈程序员站长
2022/07/13
3720
php中钩子hook的实现原理
钩子是编程里一个常见概念,非常的重要。它使得系统变得非常容易拓展,(而不用理解其内部的实现机理,这样可以减少很多工作量)。
全栈程序员站长
2022/07/19
6070
Hook(钩子技术)基本知识讲解,原理
对于Windows系统,它是建立在事件驱动机制上的,说白了就是整个系统都是通过消息传递实现的。hook(钩子)是一种特殊的消息处理机制,它可以监视系统或者进程中的各种事件消息,截获发往目标窗口的消息并进行处理。所以说,我们可以在系统中自定义钩子,用来监视系统中特定事件的发生,完成特定功能,如屏幕取词,监视日志,截获键盘、鼠标输入等等。 钩子的种类很多,每种钩子可以截获相应的消息,如键盘钩子可以截获键盘消息,外壳钩子可以截取、启动和关闭应用程序的消息等。钩子可以分为线程钩子和系统钩子,线程钩子可以监视指定线程的事件消息,系统钩子监视系统中的所有线程的事件消息。因为系统钩子会影响系统中所有的应用程序,所以钩子函数必须放在独立的动态链接库(DLL) 中。 所以说,hook(钩子)就是一个Windows消息的拦截机制,可以拦截单个进程的消息(线程钩子),也可以拦截所有进程的消息(系统钩子),也可以对拦截的消息进行自定义的处理。Windows消息带了一些程序有用的信息,比如Mouse类信息,就带有鼠标所在窗体句柄、鼠标位置等信息,拦截了这些消息,就可以做出例如金山词霸一类的屏幕取词功能。
全栈程序员站长
2022/07/21
3.6K0
Android 设计模式Template Method模式
自定义模板方法模式:定义的算法的骨架中的方法,虽然某些步骤推迟到子类中,下模板方法允许子类不能改变在的情况下,该算法的结构。算法重新定义某些步骤。
全栈程序员站长
2022/01/11
2540
关于Java的钩子函数
定义 某个事件触发后,系统会自动调用该函数,而不是人为手动调用。 比如想在java中实现c++的析构函数,我们就可以用钩子函数来实习。 特点 1,系统自动调用。 2,只需要编写函数体就行。 Java中的使用 我们常用钩子的地方是函数关闭时,也就是Jvm中异常关闭和正常关闭。 public static void main(String[] args){ Runtime.getRuntime.addShutDownHook( new Thread(()->System.out.prin
宇宙无敌暴龙战士之心悦大王
2022/02/17
1.4K0
钩子函数是什么?(函数那个小钩子哪里调出来)
先来看一段百科:钩子函数是Windows消息处理机制的一部分,通过设置“钩子”,应用程序可以在系统级对所有消息、事件进行过滤,访问在正常情况下无法访问的消息。钩子的本质是一段用以处理系统消息的程序,通过系统调用,把它挂入系统。
全栈程序员站长
2022/07/28
4880
java基础案例4-4学生和老师「建议收藏」
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/151728.html原文链接:https://javaforall.cn
全栈程序员站长
2022/08/31
7260
3.vue生命周期钩子函数有哪些?(vue生命周期的理解)
1、beforeCreate(创建前):beforeCreate钩子函数,这个时候,vue实例的挂载元素$el和数据对象data都为undefined,还未初始化。无法访问到数据和真实的dom和data中的数据,可以在这里面使用loading
全栈程序员站长
2022/07/28
8040
3.vue生命周期钩子函数有哪些?(vue生命周期的理解)
Vue进阶(十八):router.beforeEach 与 router.afterEach 钩子函数
路由跳转的时候,我们需要做一些权限判断或者其他操作。这个时候就需要使用路由钩子函数。
全栈程序员站长
2022/09/13
3.9K0
Java打印数组的四种方式「建议收藏」
toString方法是Object类中方法,作用是输出对象时调用,打印出对象名和一串16进制数,重写后可以格式化地打印数组。
全栈程序员站长
2022/09/01
5280
Java打印数组的四种方式「建议收藏」
5 分钟掌握 Python 中的 Hook 钩子函数
经常会听到钩子函数(hook function)这个概念,最近在看目标检测开源框架mmdetection,里面也出现大量Hook的编程方式,那到底什么是hook?hook的作用是什么?
Python数据科学
2020/12/15
13K0
5 分钟掌握 Python 中的 Hook 钩子函数
全局键盘钩子
这是在系统的范围内截获键盘消息,所以需要全局键盘钩子,全局键盘钩子需要DLL文件的支持,这样系统才能把DLL强行的加载到进程中去。建立一个新的DLL文件,在DllMain()函数所在的CPP中添加:
全栈程序员站长
2022/06/30
7740
全局键盘钩子
Vue进阶(三十六):created() 详解「建议收藏」
vue.js中created方法是一个生命周期钩子函数,一个vue实例被生成后会调用这个函数。一个vue实例被生成后还要绑定到某个html元素上,之后还要进行编译,然后再插入到document中。每一个阶段都会有一个钩子函数,方便开发者在不同阶段处理不同逻辑。
全栈程序员站长
2022/09/12
4K0
Vue进阶(三十六):created() 详解「建议收藏」
java新手代码大全_java新手的一串代码「建议收藏」
importjava.util.*;importjava.io.*;abstractclassGood{Stringname;doubleprice;Good(Stringname,doubleprice){this.name=name;this.price=price;}}classBookextendsGood{Stringname;…
全栈程序员站长
2022/06/24
1.8K0
java函数式编程实例(函数式编程实例)
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/128794.html原文链接:https://javaforall.cn
全栈程序员站长
2022/07/28
1.2K0
Lamda表达式详解
1、λ 希腊字母表中排序第十一位的字母,英语名称为 Lamda 2、避免匿名内部类定义过多 3、可以让你的代码看起来很简洁 4、去掉了一堆没有意义的代码,留下核心的逻辑 3、其实质属于函数式编程的概念
全栈程序员站长
2022/07/01
3150
Lamda表达式详解
Java打破双亲委派机制「建议收藏」
沿用双亲委派机制自定义类加载器很简单,只需继承ClassLoader类并重写findClass方法即可。 ①先定义一个待加载的类Test,它很简单,只是在构建函数中输出由哪个类加载器加载。
全栈程序员站长
2022/07/23
5910
推荐阅读
相关推荐
Spring Boot与事务钩子函数:概念与实战
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验