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

xxhby3vn  于 2023-04-04  发布在  Java
关注(0)|答案(7)|浏览(202)

当我偶然发现useRef时,我正在浏览hooks文档。
看看他们的例子……

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存在?

uklbhaso

uklbhaso1#

不同之处在于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);

uqcuzwp8

uqcuzwp82#

tldr

ref是一个普通的JS对象{ current: <some value> }
React.createRef()是一个返回ref { current: null }的工厂-不涉及任何魔法。
useRef(initValue)也返回一个ref { current: initValue },类似于React.createRef()此外,它将此ref存储为持久化,并在 function component 中跨多个渲染。
在类组件中使用React.createRef就足够了,因为ref对象被分配给一个示例变量,因此可以在整个组件及其生命周期中访问:

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

useRef(null)基本上是is equivalent touseState(React.createRef())[0]1

1将useRef替换为useState + createRef

tweet对我来说很有启发:
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的新旧对象引用。如果我们直接 mutateuseState的状态(与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,而不是重新发明轮子。上面是为了说明目的。

dly7yett

dly7yett3#

createRef总是返回一个新的ref,你通常会将其存储为类组件示例上的一个字段。useRef在函数组件示例的每次渲染时都会返回 * 相同的ref*。这就是为什么ref的状态可以在渲染之间保持不变,尽管你没有显式地将其存储在任何地方。
在第二个示例中,将在每次渲染时重新创建参照。

cidc1ykv

cidc1ykv4#

只是为了强调一个目的:
createRefreturn {current: null}一样简单。这是一种以最现代的方式处理ref= prop的方法,仅此而已(而基于字符串的方法太神奇了,基于回调的方法看起来太冗长了)。
useRef在渲染之前保留一些数据,并且更改它不会导致重新渲染(就像useState一样)。它们很少相关。您对基于类的组件的所有期望都转到示例字段(this.* =)看起来像是在功能组件中使用useRef实现的候选者。
假设useCallback作为有界类方法(this.handleClick = .....bind(this))工作,并且可以用useRef重新实现(但我们不应该肯定地重新发明轮子)。
另一示例是DOM引用、超时/间隔ID、任何第三方库的标识符或引用。
PS我认为React团队最好为useRef选择不同的命名,以避免与createRef混淆。可能是useAndKeep甚至usePermanent

kmpatx3s

kmpatx3s5#

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
wd2eg0qa

wd2eg0qa6#

useRef和forwardRef在React中是两个不同的东西,有不同的用例。

import React, { useRef } from 'react';

const App = () => {
  const inputRef = useRef(null);

  const handleClick = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <input type="text" ref={inputRef} />
      <button onClick={handleClick}>Focus input</button>
    </div>
  );
};

export default App;

另一方面:

import React, { forwardRef } from 'react';

const CustomInput = forwardRef((props, ref) => {
  return (
    <input type="text" ref={ref} />
  );
});

const App = () => {
  const inputRef = React.createRef();

  const handleClick = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <CustomInput ref={inputRef} />
      <button onClick={handleClick}>Focus
   </div>
)
rqdpfwrv

rqdpfwrv7#

另一个重要的补充,其他的答案。
您不能为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

相关问题