前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >TypeScript从零实现React自定义Hook,实现Vue中的watch功能。

TypeScript从零实现React自定义Hook,实现Vue中的watch功能。

作者头像
ssh_晨曦时梦见兮
发布于 2020-04-11 12:56:10
发布于 2020-04-11 12:56:10
2K00
代码可运行
举报
运行总次数:0
代码可运行

前言

在Vue中,我们经常需要用watch去观察一个值的变化,通过新旧值的对比去做一些事情。

但是React Hook中好像并没有提供类似的hook来让我们实现相同的事情

不过好在Hook的好处就在于它可以自由组合各种基础Hook从而实现强大的自定义Hook。

本篇文章就带你打造一个简单好用的use-watch hooks。

实现

实现雏形

首先分析一下Vue中watch的功能,就是一个响应式的值发生改变以后,会触发一个回调函数,那么在React中自然而然的就想到了useEffect这个hook,我们先来打造一个基础的代码雏形,把我们想要观察的值作为useEffect的依赖传入。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Callback<T> = (prev: T | undefined) => void;

function useWatch<T>(dep: T, callback: Callback<T>) {
  useEffect(() => {
   callback();
  }, [dep]);
}
复制代码

现在我们使用的时候就可以

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const App: React.FC = () => {
  const [count, setCount] = useState(0);

  useWatch(count, () => {
    console.log('currentCount: ', count);
  })

  const add = () => setCount(prevCount => prevCount + 1)

  return (
    <div>
      <p> 当前的count是{count}</p>
      {count}
      <button onClick={add} className="btn">+</button>
    </div>
  )
}
复制代码

实现oldValue

在每次count发生变化的时候,会执行传入的回调函数。

现在我们加入旧值的保存逻辑,以便于在每次调用传进去的回调函数的时候,可以在回调函数中拿到count上一次的值。

什么东西可以在一个组件的生命周期中充当一个存储器的功能呢,当然是useRef啦。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function useWatch<T>(dep: T, callback: Callback<T>) {
  const prev = useRef<T>();

  useEffect(() => {
    callback(prev.current);
    prev.current = dep;
  }, [dep]);

  return () => {
    stop.current = true;
  };
}
复制代码

这样就在每一次更新prev里保存的值为最新的值之前,先调用callback函数把上一次保留的值给到外部。

现在外部使用的时候 就可以

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const App: React.FC = () => {
  const [count, setCount] = useState(0);

  useWatch(count, (oldCount) => {
    console.log('oldCount: ', oldCount);
    console.log('currentCount: ', count);
  })

  const add = () => setCount(prevCount => prevCount + 1)

  return (
    <div>
      <p> 当前的count是{count}</p>
      {count}
      <button onClick={add} className="btn">+</button>
    </div>
  )
}
复制代码

实现immediate

其实到此为止,已经实现了Vue中watch的主要功能了,

现在还有一个问题是useEffect会在组件初始化的时候就默认调用一次,而watch的默认行为不应该这样。

现在需要在组件初始化的时候不要调用这个callback,还是利用useRef来做,利用一个标志位inited来保存组件是否初始化的标记。

并且通过第三个参数config来允许用户改变这个默认行为。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Callback<T> = (prev: T | undefined) => void;
type Config = {
  immediate: boolean;
};

function useWatch<T>(dep: T, callback: Callback<T>, config: Config = { immediate: false }) {
  const { immediate } = config;

  const prev = useRef<T>();
  const inited = useRef(false);

  useEffect(() => {
    const execute = () => callback(prev.current);

    if (!inited.current) {
      inited.current = true;
      if (immediate) {
        execute();
      }
    } else {
      execute();
    }
    prev.current = dep;
  }, [dep]);
}

复制代码

实现stop

还是通过useRef做,只是把控制ref标志的逻辑暴露给外部。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Callback<T> = (prev: T | undefined) => void;
type Config = {
  immediate: boolean;
};

function useWatch<T>(dep: T, callback: Callback<T>, config: Config = { immediate: false }) {
  const { immediate } = config;

  const prev = useRef<T>();
  const inited = useRef(false);
  const stop = useRef(false);

  useEffect(() => {
    const execute = () => callback(prev.current);

    if (!stop.current) {
      if (!inited.current) {
        inited.current = true;
        if (immediate) {
          execute();
        }
      } else {
        execute();
      }
      prev.current = dep;
    }
  }, [dep]);

  return () => {
    stop.current = true;
  };
}
复制代码

这样在外部就可以这样去停止本次观察。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const App: React.FC = () => {
  const [prev, setPrev] = useState()
  const [count, setCount] = useState(0);

  const stop = useWatch(count, (prevCount) => {
    console.log('prevCount: ', prevCount);
    console.log('currentCount: ', count);
    setPrev(prevCount)
  })

  const add = () => setCount(prevCount => prevCount + 1)

  return (
    <div>
      <p> 当前的count是{count}</p>
      <p> 前一次的count是{prev}</p>
      {count}
      <button onClick={add} className="btn">+</button>
      <button onClick={stop} className="btn">停止观察旧值</button>
    </div>
  )
}
复制代码

源码地址:

github.com/sl1673495/u…

文档地址:

文档是基于docz生成的,配合mdx还可以实现非常好用的功能预览: sl1673495.github.io/use-watch-h…

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

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

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
美丽的公主和它的27个React 自定义 Hook
在上一篇git 原理中我们在「前置知识点」中随口提到了Hook。其中,就有我们比较熟悉的React Hook。
前端柒八九
2023/10/25
1.1K0
美丽的公主和它的27个React 自定义 Hook
React-Hook最佳实践
Hooks 是 React 16.8 新增的特性,它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性,无需转化成类组件
xiaofeng123aa
2022/10/17
4K0
宝啊~来聊聊 9 种 React Hook
文章会为你讲述 React 9种 Hook 的日常用法以及进阶操作,从浅入深彻底掌握 React Hook!
19组清风
2022/02/28
1.1K0
宝啊~来聊聊 9 种 React Hook
React最佳实践
每天都在写业务代码中度过,但是呢,经常在写业务代码的时候,会感觉自己写的某些代码有点别扭,但是又不知道是哪里别扭,今天这篇文章我整理了一些在项目中使用的一些小的技巧点。
前端进击者
2021/08/20
9210
Note·React Hook
React Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
数媒派
2022/12/01
2.2K0
React 进阶:Hooks 该怎么用
之前如果我们需要抽离一些重复的逻辑,就会选择 HOC 或者 render props 的方式。但是通过这样的方式去实现组件,你打开 React DevTools 就会发现组件被各种其他组件包裹在里面。这种方式首先提高了 debug 的难度,并且也很难实现共享状态。
小生方勤
2019/06/26
1.1K0
useTypescript-React Hooks和TypeScript完全指南
React v16.8 引入了 Hooks,它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。这些功能可以在应用程序中的各个组件之间使用,从而易于共享逻辑。Hook 令人兴奋并迅速被采用,React 团队甚至想象它们最终将替换类组件。
前端森林
2020/04/23
9.1K0
useTypescript-React Hooks和TypeScript完全指南
接着上篇讲 react hook
Hook 是一个特殊的函数,使用了 JavaScript 的闭包机制,可以让你在函数组件里“钩入” React state 及生命周期等特性。Hook 不能在 class 组件中使用。这也就是我开篇说的函数式组件一把索的原因
sunseekers
2020/06/03
2.6K0
自定义Hooks解析
自定义hooks是react16.8版本引入hooks后一种全新的逻辑复用方式,相比render props和高阶组件有很大的优势!
乐圣
2022/11/19
2.9K0
React Hook实战
在React Hook出现之前的版本中,组件主要分为两种:函数式组件和类组件。其中,函数式组件通常只考虑负责UI的渲染,没有自身的状态也没有业务逻辑代码,是一个纯函数。而类组件则不同,类组件有自己的内部状态,界面的显示结果通常由props 和 state 决定,因此它也不再那么纯洁。函数式组件,类组件有如下一些缺点:
xiangzhihong
2020/12/21
2.2K0
干货 | React Hook的实现原理和最佳实践
React的组件化给前端开发带来了前所未有的体验,我们可以像玩乐高玩具一样将组件堆积拼接起来,组成完整的UI界面,在加快开发速度的同时又提高了代码的可维护性。
携程技术
2019/07/22
10.9K1
干货 | React Hook的实现原理和最佳实践
React.js和Vue.js的语法并列比较
React.js和Vue.js都是很好的框架。而且Next.js和Nuxt.js甚至将它们带入了一个新的高度,这有助于我们以更少的配置和更好的可维护性来创建应用程序。但是,如果你必须经常在框架之间切换,在深入探讨另一个框架之后,你可能会轻易忘记另一个框架中的语法。在本文中,我总结了这些框架的基本语法和方案,然后并排列出。我希望这可以帮助我们尽快掌握语法,不过限于篇幅,这篇文章只比较React.js和Vue.js,下一篇再谈Next.js个Nuxt.js。
张张
2020/05/06
10.7K0
React.js和Vue.js的语法并列比较
React Hooks-useTypescript!
在React v16.8新增了Hook,它提供了在函数组件中访问状态和React生命周期等能力,这些函数可以在程序的各个组件之间复用,达到共享逻辑的目的。
写代码的阿宗
2020/09/22
4.3K0
React useEffect中使用事件监听在回调函数中state不更新的问题
很多React开发者都遇到过useEffect中使用事件监听在回调函数中获取到旧的state值的问题,也都知道如何去解决。这个问题网上很多讲解都是直接讲是因为闭包导致获取到的是旧的state值,讲的不够清晰。我们看下具体的例子来逐步理解这个问题。
DamonLiu
2022/06/27
11.6K0
react hooks 全攻略
React Hooks 是 React 提供的一种功能,允许我们在函数组件中使用状态和其他 React 特性。使用 Hooks 可以简化函数组件中的状态管理和副作用处理。
程序员王天
2023/10/18
8160
React+TypeScript使用规范
一个采用 parameterName is Type的形式返回 boolean 值的函数,但 parameterName 必须是当前函数的参数名
用户4619307
2023/05/04
4.8K0
React Hooks教程之基础篇
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
乐圣
2022/11/19
3.1K0
React框架 Hook API
如果你刚开始接触 Hook,那么可能需要先查阅 Hook 概览。你也可以在 Hooks FAQ 章节中获取有用的信息。
郭顺发
2023/07/17
2850
超实用的 React Hooks 常用场景总结
React 在 v16.8 的版本中推出了 React Hooks 新特性。在我看来,使用 React Hooks 相比于从前的类组件有以下几点好处:
前端达人
2021/05/11
4.8K0
React系列-轻松学会Hooks
❗️❗️HOC、Render Props 等基于组件组合的方案,相当于先把要复用的逻辑包装成组件,再利用组件复用机制实现逻辑复用。自然就受限于组件复用,因而出现扩展能力受限、Ref 隔断、Wrapper Hell……等问题
落落落洛克
2021/01/08
4.4K0
React系列-轻松学会Hooks
相关推荐
美丽的公主和它的27个React 自定义 Hook
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验