当前位置:   article > 正文

react hooks系列之useRef

hooks 使用useref

react hooks系列之useRef

react hooks是 react 16.8 引入的特性,这里我们通过对react-hook-form进行分析来了解成熟的库是如何使用hook的。这将是一个系列,首先推荐 useRef

useRef

简介

在react中,我们使用Ref来获取组件的实例或者DOM元素。我们可以使用两种方式来创建 Ref

  1. import * as React from 'react'
  2. import { useState, useEffect, useRef, createRef } from 'react'
  3. export default () => {
  4. const ref1 = createRef<HTMLFormElement>()
  5. const ref2 = useRef<HTMLInputElement>()
  6. useEffect(() => {
  7. console.log(ref1)
  8. console.log(ref2)
  9. }, [])
  10. return (
  11. <form ref={ref1}>
  12. <label>用户信息</label>
  13. <input type="text" ref={ref2} />
  14. </form>
  15. )
  16. }

上面两种方式都能在组件 mounted 之后获取相关的DOM元素。在一个组件的正常的生命周期中可以大致可以分为3个阶段

  1. 从创建组件到挂载到DOM阶段。初始化props以及state, 根据state与props来构建DOM
  2. 组件依赖的props以及state状态发生变更,触发更新
  3. 销毁阶段

在第1阶段,使用createRefuseRef两者是没有区别。但是在第2阶段, 也就是更新阶段两者是有区别的。我们知道,在一个局部函数中,函数每一次执行,都会在把函数的变量重新生成一次。

  1. export default () => {
  2. const ref1 = createRef<HTMLFormElement>()
  3. const ref2 = useRef<HTMLInputElement>()
  4. const [ count, setCount ] = useState<number>(0)
  5. useEffect(() => {
  6. if (!store.ref1) {
  7. store.ref1 = ref1
  8. } else {
  9. console.log(store.ref1 === ref1)
  10. }
  11. })
  12. useEffect(() => {
  13. setTimeout(() => {
  14. setCount(1)
  15. }, 1000)
  16. }, [])
  17. return (
  18. <form ref={ref1}>
  19. <label>用户信息</label>
  20. <input type="text" ref={ref2} />
  21. </form>
  22. )
  23. }


我们使用一个外部的变量 store来存储初次所创建的ref,在我们对组件进行更新后,会发现更新后的ref与我们初次创建的ref其实并不一致。这样也就意味着 我们每更新一次组件, 就重新创建一次ref

由于有上面的问题,这在函数组件中,使用createRef去获取ref是不合理的。所以hook给我们提供一个新的API, 就是useRef。在useRef创建的ref仿佛就像外部定义的一个全局变量,不会随着组件的更新而重新创建。但组件销毁,它也会消失,不用手动进行销毁。

  1. export default () => {
  2. const ref1 = createRef<HTMLFormElement>()
  3. const ref2 = useRef<HTMLInputElement>()
  4. const [ count, setCount ] = useState<number>(0)
  5. useEffect(() => {
  6. if (!store.ref1) {
  7. store.ref1 = ref1
  8. } else {
  9. console.log('ref1:', store.ref1 === ref1)
  10. }
  11. if (!store.ref2) {
  12. store.ref2 = ref2
  13. } else {
  14. console.log('ref2:', store.ref2 === ref2)
  15. }
  16. })
  17. useEffect(() => {
  18. setTimeout(() => {
  19. setCount(1)
  20. }, 1000)
  21. }, [])
  22. return (
  23. <form ref={ref1}>
  24. <label>用户信息</label>
  25. <input type="text" ref={ref2} />
  26. </form>
  27. )
  28. }

通过上面的说明,我们知道useRef创建的ref并不会随着组件的更新而重新构建。由于这个特性,在使用react-hook的时候,可以使用useRef来存储常量。

useRef在react-hook-form中应用

现在回到我们的主题,看看react-hook-form是如何处理ref。在react-hook-form有一个API为register
源码实现如下

  1. ...
  2. function register(refOrValidationOptions, validationOptions) {
  3. if (isWindowUndefined) {
  4. return;
  5. }
  6. if (isString(refOrValidationOptions)) {
  7. registerFieldsRef({ name: refOrValidationOptions }, validationOptions);
  8. return;
  9. }
  10. if (isObject(refOrValidationOptions) && 'name' in refOrValidationOptions) {
  11. registerFieldsRef(refOrValidationOptions, validationOptions);
  12. return;
  13. }
  14. return (ref) => ref && registerFieldsRef(ref, refOrValidationOptions);
  15. }

使用闭包存储了对当前输入框的validationOptions, 返回的函数被ref的接收。这里使用了ref另外一种获取方式‘回调refs’

  1. import { useForm } from 'react-hook-form'
  2. export default () => {
  3. const { register, errors, handleSubmit } = useForm()
  4. const submit = useCallback((data, e) => {
  5. console.log(data, e)
  6. }, [])
  7. useEffect(() => {
  8. console.log(errors)
  9. })
  10. return (
  11. <form onSubmit={handleSubmit(submit)}>
  12. <label>用户信息</label>
  13. <input name="userName" ref={register({ required: true })} />
  14. {errors.userName && "Your input is required"}
  15. <button type={'submit'}>提交</button>
  16. </form>
  17. )
  18. }

这里为什么使用回调refs,而不是refs。其实理由很简单,因为后面要引用的DOM元素或者React实例是未知,我们是不知道使用者会把register注册到INPUTTEXTAREA、还是其他的第三方组件。注册一个还是多个。使用回调refs我们能够直接获取到对应的真实DOM元素或者React实例,而使用了refs就会失去这种灵活性。

如果我们继续往后面进行分析,会看到useForm这个hook中,使用了大量的useRef来存储变量,原因看前面。


而前面通过register中调用的ref对象被注册到filedsRef中。

作者:火星田园犬

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/411823
推荐阅读
相关标签
  

闽ICP备14008679号