react 进阶hook 之自定义Hook

简介: hooks是一个函数,并且是在react 函数组件中使用的,不同的hook的作用也是不一样的,例如,state hook是用来定义函数组件的状态, 而effect hook 是用来定义组件的副作用,那么自定义hook是用来干啥的呢?,自定来定义一个hook 函数,里面可以包含 多个hooks。简单点的说是,把相同逻辑的hooks封装在同一个函数里。

含义


从标题上看,自定义hook的主要是自己定义,那么对于hooks的定义又是啥呢? 简单点的回答,hooks是一个函数,并且是在react 函数组件中使用的,不同的hook的作用也是不一样的,例如,state hook是用来定义函数组件的状态, 而effect hook 是用来定义组件的副作用,那么自定义hook是用来干啥的呢?,自定来定义一个hook 函数,里面可以包含 多个hooks。简单点的说是,把相同逻辑的hooks封装在同一个函数里。


规则


1.hooks 的使用方式都是 use 开头,那么我们自己定义的也用这个use 开头,作为是一个hook 的标记,统一开发规范


2.自定义的hooks 肯定也是一个函数,并且需要和react 给我们的组件一样,需要放到顶层


作用


自定义hooks的作用让代码更加简洁,就是对代码逻辑块的封装。而hooks的作用主要是横切关注点来处理问题。处理自定义hooks可以处理横切关注点外,还有高阶组件和props render 也是来做这个事情的。


案例


在这里我们想要实现一个这样的功能,做一个每隔1s来轮询后台的方法,并且在使用一个开关,想要轮询打开就行,不想要直接关闭。下面使用两种方式来实现,一种是自定义hook的方式,另一种是 函数组件的高阶组件也可以实现这样的效果


自定义hook 案例源码


import React, { useEffect, useState } from 'react'
/**
 * 列表组件
 * @returns 
 */
function ListComp() {
  const { count, data } = useTimerReqHooks();
  const liDom = data.map((it, index) => (<li key={index}>{it}</li>));
  return (
    <>
      <p>次数: {count}</p>
      <p>数据</p>
      <ul>
        {liDom}
      </ul>
    </>)
}
/**
 * 测试组件
 * @returns 
 */
export default function TestCusHook() {
  const [hasShow, setHasShow] = useState(true);
  return (
    <div>
      <p><button onClick={() => { setHasShow(!hasShow) }}>隐藏/显示</button></p>
      {hasShow && <ListComp />}
    </div>
  )
}
/**
 * 自定义hook,做一个轮询后台的处理,每隔1s钟发一次请求(实际的请求不可能这么频繁)
 */
export function useTimerReqHooks() {
  // 计时器记录的数据
  const [count, setCount] = useState<number>(0);
  // 时间变化请求
  const [data, setData] = useState<number[]>([]);
  // 计数器
  let timer: number | null = null;
  // 副作用,发起请求
  useEffect(() => {
    timer = setInterval(() => {
      // 计时器值 + 1
      setCount(pre => pre + 1);
      // 这里用一个立即执行函数来发送请求
      (async () => {
        const res = await getData(1, 10);
        console.log(data, res, '-=====');
        // 如果想要拿到先前的数据,需要返回一个函数,不然做不到,异步的
        setData(pre => [...pre, res]);
      })()
    }, 1000)
    return () => {
      // 清空定时器
      if (timer) {
        clearInterval(timer);
        timer = null;
      }
    }
  }, [count]);
  return {
    data,
    count
  }
}
/**
 * 模拟发送请求,每一次返回一个随机数
 */
function getData(min: number, max: number): Promise<number> {
  return new Promise((resolve, reject) => {
    resolve(parseInt((Math.random() * (max - min)).toString(), 10) + min)
  })
}


自定义hook 效果


20210407144515360.gif

20210407145119265.png



组件树是纯粹的,没有添加任何的其他组件,方便调试


高阶组件


import React, { PureComponent } from 'react'
/**
 * 
 * @param comp 高阶组件的接口
 * @returns 
 */
interface IWithTimerReqS {
  // 当前次数
  count: number,
  // 获取的结果
  data: number[]
}
/**
 * 显示组件
 */
interface ITestCusCompS extends Partial<IWithTimerReqS> {
  // 是否展示组件
  hasShow: Boolean,
}
/**
 * 高阶组件
 */
function withTimerReq(Comp: React.ComponentClass<IWithTimerReqS>) {
  return class withTimerReqs extends PureComponent<{}, IWithTimerReqS> {
    state: IWithTimerReqS = {
      count: 0,
      data: [],
    }
    private timer: number | null = null;
    // 组件初始化的时候进行启动定时器
    componentDidMount() {
      this.setData();
    }
    // 数据更新进行操作
    componentDidUpdate(prevProps: {}, prevState: IWithTimerReqS) {
      this.setData();
    }
    private setData(){
      if(this.timer){
        clearInterval(this.timer);
        this.timer = null;
      }
      // 启动定时器
      this.timer =  setInterval(() => {
        // 计时器值 + 1
        this.setState(pre => {
          return {
            ...pre,
            count: pre.count + 1
          }
        });
        // 这里用一个立即执行函数来发送请求
        (async () => {
          const res = await getData(1, 10);
          console.log(this.state.data, res, '-=====');
          this.setState(pre =>{
            return {
              ...pre,
            data: [...pre.data, res]
            }
          });
        })()
      }, 1000)
    }
    // 组件卸载,清空定时器
    componentWillUnmount() {
      if(this.timer){
        clearInterval(this.timer);
        this.timer = null;
      }
    }
    render() {
      return (<>
        <Comp  {...this.state} />
      </>)
    }
  }
}
/**
 * 列表组件
 */
class ListComp extends PureComponent<IWithTimerReqS> {
 render(){
  const liDom = this.props.data.map((it, index) => (<li key={index}>{it}</li>));
   return (
    <>
    <p>次数: {this.props.count}</p>
    <p>数据</p>
    <ul>
      {liDom}
    </ul>
  </>
   )
 }
}
// 使用高阶组件包裹
const WithComp = withTimerReq(ListComp)
export default class TestCusComp extends PureComponent<{}, ITestCusCompS> {
  state: ITestCusCompS = {
    hasShow: true
  }
  render() {
    return (
      <div>
        <p><button onClick={() => { this.setState({ hasShow: !this.state.hasShow }) }}>隐藏/显示</button></p>
        {this.state.hasShow && <WithComp />}
      </div>
    )
  }
}
/**
 * 模拟发送请求,每一次返回一个随机数
 */
function getData(min: number, max: number): Promise<number> {
  return new Promise((resolve, reject) => {
    resolve(parseInt((Math.random() * (max - min)).toString(), 10) + min)
  })
}


高阶组件效果


20210407150200997.gif

20210407150142404.png


总结


虽然两者实现的效果都是一样的,但是类组件中的代码量比hooks 多了大概50行左右,而且还比较绕。但是hooks 就比较纯粹,组件结果不增加,做到真正的横向关注点。

相关文章
|
1月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
163 2
|
3月前
|
设计模式 存储 前端开发
React开发设计模式及原则概念问题之自定义Hooks的作用是什么,自定义Hooks设计时要遵循什么原则呢
React开发设计模式及原则概念问题之自定义Hooks的作用是什么,自定义Hooks设计时要遵循什么原则呢
|
2月前
|
前端开发
React给antd中TreeSelect组件左侧加自定义图标icon
本文介绍了如何在React中为Ant Design的TreeSelect组件的每个树节点添加自定义图标,并解决了因缺少key属性而导致的警告问题,展示了如何通过递归函数处理treeData数据并为每个节点添加图标。
115 2
React给antd中TreeSelect组件左侧加自定义图标icon
|
2月前
|
前端开发 Python
React技术栈-React路由插件之自定义组件标签
关于React技术栈中React路由插件自定义组件标签的教程。
54 4
React技术栈-React路由插件之自定义组件标签
|
1月前
|
前端开发 JavaScript API
自定义React Hooks综合指南
本文介绍了React Hooks及其在组件开发中的作用,重点讲解了自定义Hook的创建和使用方法。通过实例展示了如何创建`useWindowWidth`、`useFetch`和`useForm`等自定义Hook,并分享了使用自定义Hook的最佳实践。文章强调了自定义Hook在提高代码复用性和组件可维护性方面的重要性。
57 0
|
3月前
|
前端开发 JavaScript
|
3月前
|
前端开发
React 中的 Hook 概念
【8月更文挑战第31天】
33 0
|
4月前
|
前端开发
React useImperativeHandle Hook
【7月更文挑战第1天】React useImperativeHandle Hook
26 3
|
4月前
|
前端开发 JavaScript 数据格式
react18【系列实用教程】Hooks (useState,useReducer,useRef,useEffect,useContext,useMemo,useCallback,自定义 Hook )
react18【系列实用教程】Hooks (useState,useReducer,useRef,useEffect,useContext,useMemo,useCallback,自定义 Hook )
93 1
|
4月前
|
存储 前端开发 JavaScript
react hooks 学习进阶
【7月更文挑战第12天】 React Hooks(自16.8版起)让函数组件能处理状态和副作用。useState用于添加状态管理,useEffect处理副作用,useContext共享数据,useReducer处理复杂状态逻辑,useRef获取引用。进阶技巧涉及性能优化,如useMemo和useCallback,以及遵循规则避免在不适当位置调用Hooks。理解异步更新机制和结合Redux等库提升应用复杂性管理。持续学习新技巧是关键。
54 0