`useRef` 和 `createRef` 有什么区别?

IT技术 javascript reactjs react-hooks
2021-01-29 05:13:15

当我偶然发现useRef.

看看他们的例子……

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    // `current` points to the mounted text input element
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

……好像useRef可以代替createRef

function TextInputWithFocusButton() {
  const inputRef = createRef(); // what's the diff?
  const onButtonClick = () => {
    // `current` points to the mounted text input element
    inputRef.current.focus();
  };
  return (
    <>
      <input ref={inputRef} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

为什么我需要一个用于 refs 的钩子?为什么useRef存在?

5个回答

不同之处在于它createRef总是会创建一个新的 ref。在基于类的组件中,您通常会在构造期间将 ref 放在实例属性中(例如this.input = createRef())。您在功能组件中没有此选项。useRef负责每次返回与初始渲染相同的 ref。

这是一个示例应用程序,演示了这两个函数的行为差异:

import React, { useRef, createRef, useState } from "react";
import ReactDOM from "react-dom";

function App() {
  const [renderIndex, setRenderIndex] = useState(1);
  const refFromUseRef = useRef();
  const refFromCreateRef = createRef();
  if (!refFromUseRef.current) {
    refFromUseRef.current = renderIndex;
  }
  if (!refFromCreateRef.current) {
    refFromCreateRef.current = renderIndex;
  }
  return (
    <div className="App">
      Current render index: {renderIndex}
      <br />
      First render index remembered within refFromUseRef.current:
      {refFromUseRef.current}
      <br />
      First render index unsuccessfully remembered within
      refFromCreateRef.current:
      {refFromCreateRef.current}
      <br />
      <button onClick={() => setRenderIndex(prev => prev + 1)}>
        Cause re-render
      </button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

编辑 1rvwnj71x3

d= (^-^ ) 优点ref是不限,甚至可以装一个简单的数字;但为什么是.current必需的(不像useState钩子)?找到原因:只是为了让.current引用通过,就像真正的类的字段一样,没有奇怪的setter。(大声笑,我想知道现在函数与真正的类相比有多慢。)
2021-04-09 05:13:15

createRef总是返回一个新的 ref,您通常会将其存储为类组件实例上的字段。在每次渲染功能组件的实例时useRef返回相同的 ref这就是允许 ref 的状态在渲染之间保持不变的原因,尽管您没有明确地将它存储在任何地方。

在您的第二个示例中,将在每次渲染时重新创建 ref。

我从上下文中的理解仅推断 useRef 是一个在内部使用 createRef 的自定义钩子。感谢您分享知识。
2021-03-20 05:13:15
在我尝试回答这个问题之前,我看到了那个链接,它在你分享的链接中在哪里说明了这个事实?我没找到?:)
2021-03-22 05:13:15
我分享的链接显示了一个useRef由 React 开发人员发布的简化实现它与简单地调用不同createRef,因为createRef它不是一个钩子,并且不会在调用之间保持任何状态。Ryan Cogswell 的回答也有一个很好的例子来说明差异。
2021-03-23 05:13:15
这是不正确的,您有参考资料来支持您的陈述吗?
2021-03-28 05:13:15
这里有一位 React 开发人员的评论,解释了它是如何工作的:reddit.com/r/reactjs/comments/a2pt15/...我很想知道您认为这个答案有什么不正确。
2021-04-02 05:13:15

域名

Aref是一个普通的 JS 对象{ current: <some value> }

React.createRef()是一家返回 ref 的工厂{ current: null }-不涉及魔法

useRef(initValue)还返回一个{ current: initValue }类似于React.createRef(). 此外,它记住此 ref 以便在函数组件中的多个渲染中保持持久性

React.createRef在类组件中 使用就足够了,因为 ref 对象被分配给一个实例变量,因此可以在整个组件及其生命周期中访问:
this.myRef = React.createRef(); // stores ref in "mutable" this context (class)

useRef(null)基本上相当于 useState(React.createRef())[0] 1


1替换useRefuseState+createRef

以下推文对我很有启发:

useRef()基本上是useState({current: initialValue })[0]

根据本tldr节的见解,我们现在可以进一步得出结论:

useRef(null)基本上是useState(React.createRef())[0]

上面的代码“滥用”useState以保留从React.createRef(). [0]只是选择的value部分useState-[1]将是二传手。

useStateuseRef. 更正式地说,useState当通过其 setter 方法设置新值时,React 会比较 的旧对象引用和新对象引用如果我们直接改变的状态useState(与 setter 调用相反),它的行为或多或少会变成等价useRef,因为不再触发重新渲染:

// Example of mutaing object contained in useState directly
const [ref] = useState({ current: null })
ref.current = 42; // doesn't cause re-render

注意:不要这样做!使用优化的useRefAPI 而不是重新发明轮子。以上是为了说明目的。

只是为了突出一个目的:

createRef就像 一样简单return {current: null}这是一种以ref=最现代的方式处理prop 的方法,就是这样(而基于字符串的方式太神奇了,基于回调的看起来太冗长了)。

useRef在渲染之前保留一些数据并且更改它不会导致重新渲染(就像useState那样)。他们很少有关联。您对基于类的组件所期望的一切都转到实例字段(this.* =)看起来像是要useRef在功能组件中实现的候选对象

useCallback作为有界类方法(this.handleClick = .....bind(this))可以重新实现(但我们肯定不应该重新发明轮子)useRef

另一个示例是 DOM 引用、超时/间隔 ID、任何 3rd 方库的标识符或引用。

PS 我相信 React 团队最好选择不同的命名,useRef以避免与createRef. 也许useAndKeep甚至usePermanent

另一个但重要的补充其他人的答案。

您无法为 设置新值createRef但是你可以为useRef.

const ur = useRef();
const cr = createRef();

ur.current = 10; // you can do it, and value is set
cr.current = 10; // you can, but it's no good, it will not change it
ref 是一个普通对象,您可以current像往常一样更改其属性(刚刚测试过)。没关系,如果 ref 是通过useRef创建的createRef
2021-03-27 05:13:15