头图

总览

当我们在一个函数组件中使用一个字符串作为ref时,会产生"Function components cannot have string refs"错误。为了解决该错误,使用useRef()钩子来得到一个可变的ref对象,这样你就可以在组件中作为ref使用。

function-components-cannot-have-string-refs.png

这里有个示例用来展示错误是如何发生的。

// App.js

export default function App() {
  // A string ref has been found within a strict mode tree.
  // ⛔️ Function components cannot have string refs.
  // We recommend using useRef() instead.
  return (
    <div>
      <input type="text" id="message" ref="msg" />
    </div>
  );
}

上述代码片段的问题在于,我们使用了字符串作为ref

useRef

为了解决该错误,使用useRef钩子来获取可变的ref对象。

// App.js

import {useEffect, useRef} from 'react';

export default function App() {
  const refContainer = useRef(null);

  useEffect(() => {
    // 👇️ this is reference to input element
    console.log(refContainer.current);

    refContainer.current.focus();
  }, []);

  return (
    <div>
      <input type="text" id="message" ref={refContainer} />
    </div>
  );
}

useRef()钩子可以被传递一个初始值作为参数。该钩子返回一个可变的ref对象,其.current属性被初始化为传递的参数。

需要注意的是,我们必须访问ref对象上的current属性,以获得对我们设置了ref属性的input元素的访问。

当我们传递ref属性到元素上时,比如说,<input ref={myRef} /> 。React将ref对象上的.current属性设置为相应的DOM节点。

useRef钩子创建了一个普通的JavaScript对象,但在每次渲染时都给你相同的ref对象。换句话说,它几乎是一个带有.current属性的记忆化对象值。

不会重新渲染

应该注意的是,当你改变refcurrent属性的值时,不会引起重新渲染。

例如,一个ref不需要包含在useEffect钩子的依赖数组中,因为改变它的current属性不会引起重新渲染。

// App.js

import {useEffect, useRef} from 'react';

export default function App() {
  const refContainer = useRef(null);

  const refCounter = useRef(0);

  useEffect(() => {
    // 👇️ this is reference to input element
    console.log(refContainer.current);
    refContainer.current.focus();

    // 👇️ incrementing ref value does not cause re-render
    refCounter.current += 1;
    console.log(refCounter.current);
  }, []);

  return (
    <div>
      <input type="text" id="message" ref={refContainer} />
    </div>
  );
}

例子中的useEffect钩子只运行了2次,因为useRef在其内容发生变化时并没有通知我们。

改变对象的current属性并不会导致重新渲染。


chuck
300 声望41 粉丝