' useRef '和' createRef '之间的区别是什么?

我在翻阅hooks文档时偶然发现了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>
</>
);
}

为什么我需要一个挂钩裁判?为什么useRef存在?

118878 次浏览

createRef总是返回一个新的ref,你通常会把它存储为类组件实例的一个字段。useRef在函数组件实例的每次渲染时返回相同的引用。这是什么允许在渲染之间保持ref的状态,尽管你没有显式地将它存储在任何地方。

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

不同之处在于createRef总是会创建一个新的ref。在基于类的组件中,你通常会在构造过程中将ref放在实例属性中(例如this.input = createRef())。在函数组件中没有这个选项。useRef负责每次返回与初始呈现时相同的引用。

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

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);

< a href = " https://codesandbox。io/s/1rvwnj71x3" rel="noreferrer">Edit 1rvwnj71x3

为了强调一个目的:

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

useRef在呈现前保留一些数据,改变它不会导致重新呈现(像useState那样)。他们之间很少有联系。你所期望的基于类的组件转到实例字段(this.* =)的所有内容看起来都像是在函数组件中使用useRef实现的候选。

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

另一个例子是DOM引用,超时/间隔id,任何第三方库的标识符或引用。

另外,我认为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

tldr

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

React.createRef()是一个返回ref { current: null } - 没有魔法的工厂。

useRef(initValue)也返回一个类似于React.createRef()的ref { current: initValue }除了,它这个引用在功能组件中的多个渲染中持久化。

在类组件中使用React.createRef就足够了,因为ref对象是赋值给实例变量,因此可以在整个组件及其生命周期中访问:

this.myRef = React.createRef(); // stores ref in "mutable" this context (class)

useRef(null)基本上是相当于 useState(React.createRef())[0] < >强1 < / >强


useState + createRef替换useRef

下面的推特对我有启发:

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

根据tldr部分的内容,我们现在可以进一步得出结论:

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

以上代码“滥用”;useState持久化从React.createRef()返回的ref。[0]只是选择useState的值部分- [1]将是setter。

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

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

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

ref是一个普通的JS对象{current:}。

React.useRef(initValue) return a ref { current: initValue }
it is remember ref value across multiple render of function component.
It is advise to use in Function component
    

React.createRef(initValue) also return a ref  { current: initValue }
it is not remember ref value across multiple render of function components. It is advise to use in class based component