第33节——useRef

一、概念

useRef,他的作用是“勾住”某些组件挂载完成或重新渲染完成后才拥有的某些对象,并返回该对象的引用。该引用在组件整个生命周期中都固定不变,该引用并不会随着组件重新渲染而失效。返回一个可变的 ref 对象,该对象只有个 current 属性,初始值为传入的参数( initialValue )。返回的 ref 对象在组件的整个生命周期内保持不变。当更新 current 值时并不会 re-render ,这是与 useState 不同的地方。更新 useRef 是 side effect (副作用),所以一般写在 useEffect 或 event handler 里。useRef 类似于类组件的 this

const refContainer = useRef(initialValue);

二、useRef是来解决什么问题的

1、JSX组件转换后对应的真实DOM对象。如何获取input的真实dom

useRef只适合“勾住”小写开头的类似原生标签的组件。如果是自定义的react组件(自定义的组件必须大写字母开头),那么是无法使用useRef(当然也有一些奇淫技巧后面我们后续课程会讲😈)的。比如,我们如何获取这个 真实DOM呢。那么就可以使用useRef

初始化input聚焦
import React,{useEffect,useRef} from 'react'


function Component() {
  //先定义一个inputRef引用变量,用于“勾住”挂载网页后的输入框
  const inputRef = useRef(null);


  useEffect(() => {
    //inputRef.current就是挂载到网页后的那个输入框,一个真实DOM,因此可以调用html中的方法focus()
    inputRef.current.focus();
  },[]);


  return <div>
    {/* 通过 ref 属性将 inputRef与该输入框进行“挂钩” */}
    <input type='text' ref={inputRef} />
  </div>
}
export default Component

2、在useEffect中创建的变量,如何在useEffect 以外的地方,获取并引用

例子

1、组件中有一个变量count,当该组件挂载到网页后,count每秒自动 +1。

2、组件中有一个按钮,点击按钮可以停止count自动+1

import React,{useState,useEffect,useRef} from 'react'


function Component() {
  const [count,setCount] =  useState(0);
  const timerRef = useRef(null);//先定义一个timerRef引用变量,用于“勾住”useEffect中通过setIntervale创建的计时器


  useEffect(() => {
    //将timerRef.current与setIntervale创建的计时器进行“挂钩”
    timerRef.current = setInterval(() => {
      setCount((prevData) => { return prevData +1});
    }, 1000);
    return () => {
      //通过timerRef.current,清除掉计时器
      clearInterval(timerRef.current);
    }
  },[]);


  const clickHandler = () => {
    //通过timerRef.current,清除掉计时器
    clearInterval(timerRef.current);
  };


  return (
    <div>
      {count}
      <button onClick={clickHandler} >stop</button>
    </div>
  )
}


export default Component

4、父组件调用子组件内的方法

注意:除非情况非常特殊,否则一般情况下都不要采用 父组件调用子组件的函数 这种策略

实现思路

父组件中通过 useRef 定义一个钩子变量,例如 childFunRef

父组件通过参数配置,将 childFunRef 传递给子组件

子组件在自己的 useEffect() 中定义一个函数,例如 doSomting()

划重点:一定要在 useEffect() 中定义 doSomting(),不能直接在子组件内部定义。

因为如果 doSomting() 定义在子组件内部,那么就会造成每一次组件刷新都会重新生成一份 doSomthing()

然后将 doSomting() 赋值到 childFunRef.current 中

这样,当父组件想调用子组件中的 doSomting() 时,可执行 childFunRef.current.doSomting()

父组件
import { useRef } from "react";
import ChildComponent from "./child";


const ParentComponent = () => {
  const childFunRef = useRef();
  const handleOnClick = () => {
    if (childFunRef.current) {
      childFunRef.current.doSomething();
    }
  };
  return (
    <div>
      <ChildComponent funRef={childFunRef} />
      <button onClick={handleOnClick}>执行子项的doSomething()</button>
    </div>
  );
};


export default ParentComponent;
子组件
import { useEffect, useState } from "react";


const ChildComponent = ({ funRef }) => {
  const [num, setNum] = useState(0);
  useEffect(() => {
    const doSomething = () => {
      setNum(Math.floor(Math.random() * 100));
    };
    funRef.current = { doSomething }; //在子组件中修改父组件中定义的childFunRef的值
  }, [funRef]);
  return <div>{num}</div>;
};


export default ChildComponent;

三、useRef与createRef的区别

1、useRef是针对函数组件的,如果是类组件则使用React.createRef()。

2、React.createRef()也可以在函数组件中使用。useRef只能在react hooks中使用

3、createRef每次都会返回个新的引用;而useRef不会随着组件的更新而重新创建

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值