useRef 、createRef 的区别及useRef其它用途分享

835 阅读2分钟

1、分别用useRef 、createRef 获取子组件的 ReactDom

1.1 React.createRef (类组件、函数组件都可以使用)

  • 类组件上创建使用
import React from 'react'

export default class MyComponent extends React.Component {
  constructor(props) {
    super(props);

    this.inputRef = React.createRef();
  }

  render() {
    return <input type="text" ref={this.inputRef} />;
  }

  componentDidMount() {
    this.inputRef.current.focus();
  }
}
  • 在函数组件上创建使用
import React from 'react'

const MyComponent = () => {
  const inputRef = React.createRef();
 
  const onButtonClick = () => {
    console.log(inputRef.current)
  };
  
  return <input type="text" ref={inputRef} />;
}

export default MyComponent;

1.2 React.useRef ( 因为是一个hook, 所以只能在函数式组件中使用)

import React from 'react'

const MyComponent = () => {
  const inputRef = React.useRef(null);
  
  const onButtonClick = () => {
    inputRef.current.focus();
  };
  return (
    <>
      <input ref={inputRef} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

export default MyComponent;

1.3 思考: 在函数式组件中,React.createRef 和 React.useRef 好像都能获取到子组件的 ReactDom ,并且打印出来,没啥区别啊??? 为啥还要新增一个hooks啊?

2、useRef 其它用途分享

思考不明白上面的问题,去官方文档看 zh-hans.reactjs.org/docs/hooks-…

本质上,useRef 就像是可以在其 .current 属性中保存一个可变值的“盒子”。

你应该熟悉 ref 这一种访问 DOM 的主要方式。如果你将 ref 对象以 <div ref={myRef} /> 形式传入组件,则无论该节点如何改变,React 都会将 ref 对象的 .current 属性设置为相应的 DOM 节点。

然而,useRef() 比 ref 属性更有用。它可以很方便地保存任何可变值,其类似于在 class 中使用实例字段的方式。

这是因为它创建的是一个普通 Javascript 对象。而 useRef() 和自建一个 {current: ...} 对象的唯一区别是,useRef 会在每次渲染时返回同一个 ref 对象。

请记住,当 ref 对象内容发生变化时,useRef 并不会通知你。变更 .current 属性不会引发组件重新渲染。如果想要在 React 绑定或解绑 DOM 节点的 ref 时运行某些代码,则需要使用回调 ref 来实现。
--- 抄的官网

看了文档介绍后,知道了useRef 有其它用途,它可以很方便地保存任何可变值,那有啥用??

2.1 使用 useRef 存储值,实现一个轻量级状态管理器 store

2.2 用于防止其他hook导致的重新渲染, 因为 useRef 会在每次渲染时返回同一个 ref 对象

  • 分享hooks版本的简单节流函数案例, (在支付宝小程序中实战用法),因为函数式组件 hooks的渲染机制,当hooks触发更新的时候,整个函数都会重新执行,每次都是不同、独立的函数,所以js的节流函数就不起作用了(包括鲁大师的节流函数)
function useThrottle(fn, delay) {

  // 用于防止其他hook导致的重新渲染
  const { current } = useRef(null);

  return function (...args) {
    if (!current.timer) {
      current.timer = setTimeout(() => {
        delete current.timer;
      }, delay);
      fn(...args);
    }
  }
}