如何在 React 中使用 forwardRef()? [英] How can I use forwardRef() in React?

查看:208
本文介绍了如何在 React 中使用 forwardRef()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前在我的 React 应用中收到以下错误:

<块引用>

不能给函数组件提供引用.尝试访问此参考将失败.你的意思是使用 React.forwardRef() 吗?

如何使用 forwardRef() 解决此问题?

我的代码如下:

const 服务:FunctionComponent = (): ReactElement =>{const servicesRef = useRef(null);返回 (<布局><ServicesList ref={servicesRef}/></布局>);};导出默认服务;const ServicesList: React.FunctionComponent = ({ children }: Props) =>{返回 (<section className="my-24 md:my-32">{儿童&&孩子们}</节>);};导出默认服务列表;

解决方案

forwardRef api,(与 useImperativeHandle 挂钩)可让您自定义引用的方式和位置放置在您的自定义组件中.此外,forwardRef 是将 ref 传递给自定义函数组件的唯一方法.

首先,重要的是要了解 refs 在类组件、函数组件和常规 DOM 元素上的工作方式不同.

来自文档:

<块引用>

ref 的值因节点类型而异:

  1. 当 ref 属性用于 HTML 元素时,在带有 React.createRef() 的构造函数接收底层 DOM元素作为其当前属性.
  2. 当 ref 属性用于自定义类组件,ref 对象接收挂载的实例组件作为其当前.
  3. 你不能在上面使用 ref 属性函数组件,因为它们没有实例.

以下是在不同元素类型上使用引用的方法示例:

1. 对 DOM 元素的引用为您提供了对 DOM 节点本身的引用:

function AutoFocusInput() {const inputRef = useRef(null);//此效果仅在组件挂载后运行一次(如 componentDidMount)useEffect(() => {//对常规 DOM 元素的引用(例如input"标签)可以访问 DOM 节点inputRef.current.focus();}, []);返回 }

2. 类组件上的 Ref 使我们可以访问实例,以及它的所有方法和字段:

class Child extends Component {状态 = {颜色:红色"}切换颜色 = () =>this.setState({color: this.state.color === "red" ? "blue": "red"})使成为() {return <div style={{backgroundColor: this.state.color}}>yo</div>}}类父扩展组件{childRef = createRef();handleButtonClicked = () =>{//类组件上的引用:保存类组件实例,//允许我们调用它的方法!this.childRef.current.toggleColor();}使成为() {返回 (<div><button onClick={this.handleButtonClicked}>切换颜色!</button><子引用={childRef}/>

);}}

3. 现在,终于回答你的问题了.Refs 不能传递给函数组件,因为它们没有实例!

将 ref 传递给函数组件的唯一方法是使用 forwardRef.使用 forwardRef 时,您可以简单地将 ref 传递给 DOM 元素,这样父元素就可以像示例 1 中那样访问它,或者您可以使用 useImperativeHandle 钩子创建具有字段和方法的对象,这将类似于示例 2.

3.1 简单地将 ref 传递给 DOM 元素:

//只有在使用 forwardRef 时,函数组件才会接收两个参数,//props 和 ref (通常组件只获取 props 参数).const RedInput = forwardRef((props, ref) => {//将 ref 传递给 DOM 元素,//这样父节点就有对 DOM 节点的引用return <input style={{color: "red"}} {...props} ref={ref}/>});功能自动对焦输入(){const inputRef = useRef(null);//此效果仅在组件挂载后运行一次(如 componentDidMount)useEffect(() => {//函数组件上的引用被转发到一个常规的 DOM 元素,//所以现在父节点可以访问 DOM 节点,包括它的 focus 方法.//注意 ref 的用法和普通的一样//DOM 元素,如示例 1 所示!inputRef.current.focus();}, []);return }

3.2 将父引用附加到自定义对象:

要将函数或字段附加到 ref,就像您可以使用类组件的实例一样,您需要使用 `useImperativeHandle` 钩子:

const Child = forwardRef((props, ref) => {const [color, setColor] = useState("red");//自定义父级将在其 ref.current 中获得的值://将 ref 对象作为第一个参数传递给 useImperativeHandle.//然后,无论从第二个参数中的回调返回什么,//将是 ref.current 的值.//这里我返回一个带有 toggleColor 方法的对象,供父级使用:useImperativeHandle(ref, () => ({切换颜色:() =>setColor(prevColor => prevColor === "red" ? "blue" : "red")}));return <div style={{backgroundColor: color}}>yo</div>;});类父扩展组件{childRef = createRef();handleButtonClicked = () =>{//Ref 传递给包装在 forwardRef 中的函数组件.//请注意,此父组件没有任何更改//与示例 2 中的类组件相比!this.childRef.current.toggleColor();}使成为() {返回 (<div><button onClick={this.handleButtonClicked}>切换颜色!</button><子引用={childRef}/>

);}}

I'm currently receiving the following error in my React app:

Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

How can I fix this using forwardRef()?

My code is as follows:

const Services: FunctionComponent = (): ReactElement => {
  const servicesRef = useRef(null);

  return (
    <Layout>
      <ServicesList ref={servicesRef} />
    </Layout>
  );
};
export default Services;



const ServicesList: React.FunctionComponent = ({ children }: Props) => {
  return (
    <section className="my-24 md:my-32">
      {children && children}
    </section>
  );
};

export default ServicesList;

解决方案

The forwardRef api, (coupled with the useImperativeHandle hook) lets you customize how and where your refs are placed inside your custom components. Also, forwardRef is the only way to pass a ref to your custom function components.

First, its important to understand that refs work differently on class components, function components, and regular DOM elements.

From the docs:

The value of the ref differs depending on the type of the node:

  1. When the ref attribute is used on an HTML element, the ref created in the constructor with React.createRef() receives the underlying DOM element as its current property.
  2. When the ref attribute is used on a custom class component, the ref object receives the mounted instance of the component as its current.
  3. You may not use the ref attribute on function components because they don’t have instances.

Here are examples for the ways to use refs on the different element types:

1. Ref on a DOM element gives you a reference to the DOM Node itself:

function AutoFocusInput() {
  const inputRef = useRef(null);
  // This effect runs only once after the component mounts (like componentDidMount)
  useEffect(() => {
    // refs on regular DOM elements (e.g. the "input" tag) have access to the DOM node
    inputRef.current.focus();
  }, []);
  return <input ref={inputRef} />
}

2. Ref on a class component gives us access to the instance, with all of it's methods and fields:

class Child extends Component {
  state = {color: "red"}
  toggleColor = () => this.setState({color: this.state.color === "red" ? "blue" : "red"})
  render() {
    return <div style={{backgroundColor: this.state.color}}>yo</div>
  }
}

class Parent extends Component {
  childRef = createRef();
  handleButtonClicked = () => {
    // refs on class components: hold the class component instance, 
    // allowing us to call its methods!
    this.childRef.current.toggleColor();
  }
  render() {
    return (
      <div>
        <button onClick={this.handleButtonClicked}>toggle color!</button>
        <Child ref={childRef} />
      </div>
    );
  }
}

3. Now, to finally answer your question. Refs can't be passed to function components, because They don't have instances!

The only way to pass a ref to a function component is using forwardRef. When using forwardRef, you can simply pass the ref to a DOM element, so the parent can access it like in example 1, or you could create an object with fields and methods using the useImperativeHandle hook, which would be similar to eample 2.

3.1 Simply passing a ref to a DOM element:

// Only when using forwardRef, the function component receives two arguments, 
// props and ref (Normally the component only gets the props argument).
const RedInput = forwardRef((props, ref) => {
  // passing the ref to a DOM element, 
  // so that the parent has a reference to the DOM node
  return <input style={{color: "red"}} {...props} ref={ref} />
});

function AutoFocusInput() {
  const inputRef = useRef(null);
  // This effect runs only once after the component mounts (like componentDidMount)
  useEffect(() => {
    // ref on function component is forwarded to a regular DOM element, 
    // so now the parent has access to the DOM node including its focus method.
    // Note that the ref usage is the same as a regular 
    // DOM element, like in example 1!
    inputRef.current.focus();
  }, []);
  return <RedInput ref={inputRef} />
}

3.2 Attaching the parent ref to a custom object:

To attach functions or fields to the ref, like you could do with the instance of a class component, you need to use the `useImperativeHandle` hook:

const Child = forwardRef((props, ref) => {
  const [color, setColor] = useState("red");
  // To customize the value that the parent will get in their ref.current: 
  // pass the ref object to useImperativeHandle as the first argument. 
  // Then, whatever will be returned from the callback in the second argument, 
  // will be the value of ref.current. 
  // Here I return an object with the toggleColor method on it, for the parent to use:
  useImperativeHandle(ref, () => ({
    toggleColor: () => setColor(prevColor => prevColor === "red" ? "blue" : "red")
  }));
  return <div style={{backgroundColor: color}}>yo</div>;
});


class Parent extends Component {
  childRef = createRef();
  handleButtonClicked = () => {
    // Ref passed to a function component wrapped in forwardRef.
    // Note that nothing has changed for this Parent component
    // compared with the class component in example 2!
    this.childRef.current.toggleColor();
  }
  render() {
    return (
      <div>
        <button onClick={this.handleButtonClicked}>toggle color!</button>
        <Child ref={childRef} />
      </div>
    );
  }
}

这篇关于如何在 React 中使用 forwardRef()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆