如何访问父组件中子组件的引用

时间:2016-06-05 21:41:15

标签: reactjs

如果我有类似

的话
<Parent>
  <Child1 />
  <Child2 />
  <Child3 />
</Parent>

我希望从Child2访问refs="child2refs",我该怎么办?

7 个答案:

答案 0 :(得分:54)

推荐用于16.3之前的React版本

如果无法避免,则从React docs中提取的建议模式为:

import React, { Component } from 'react';

const Child = ({ setRef }) => <input type="text" ref={setRef} />;

class Parent extends Component {
    constructor(props) {
        super(props);
        this.setRef = this.setRef.bind(this);
    }

    componentDidMount() {
        // Calling a function on the Child DOM element
        this.childRef.focus();
    }

    setRef(input) {
        this.childRef = input;
    }

    render() {
        return <Child setRef={this.setRef} />
    }
}

将功能转发为 this的支柱。当React调用孩子的 ref道具setRef时,它会将孩子 ref分配给父母的 childRef财产。

推荐用于React&gt; = 16.3

参考转发是一项选择加入功能,可让某些组件接收他们收到的参考,并将其进一步向下传递(换句话说,“转发”给孩子。

我们创建组件,用ref转发他们的React.forwardRef。 返回的组件 ref prop必须与返回类型React.createRef的类型相同。每当React挂载DOM节点时,使用current创建的ref的属性React.createRef将指向底层DOM节点。

import React from "react";

const LibraryButton = React.forwardRef((props, ref) => (
  <button ref={ref} {...props}>
    FancyButton
  </button>
));

class AutoFocus extends React.Component {
  constructor(props) {
    super(props);
    this.childRef = React.createRef();
    this.onClick = this.onClick.bind(this);
  }

  componentDidMount() {
    this.childRef.current.focus();
  }

  onClick() {
    console.log("fancy!");
  }

  render() {
    return <LibraryButton onClick={this.onClick} ref={this.childRef} />;
  }
}

转发引用HOC示例

已创建的组件正在将其ref转发给子节点。

function logProps(Component) {
  class LogProps extends React.Component {
    componentDidUpdate(prevProps) {
      console.log('old props:', prevProps);
      console.log('new props:', this.props);
    }

    render() {
      const {forwardedRef, ...rest} = this.props;

      // Assign the custom prop "forwardedRef" as a ref
      return <Component ref={forwardedRef} {...rest} />;
    }
  }

  // Note the second param "ref" provided by React.forwardRef.
  // We can pass it along to LogProps as a regular prop, e.g. "forwardedRef"
  // And it can then be attached to the Component.
  return React.forwardRef((props, ref) => {
    return <LogProps {...props} forwardedRef={ref} />;
  });
}

请参阅React docs中的Forwarding Refs

答案 1 :(得分:17)

  1. 在子组件内部添加一个ref到您需要的节点
  2. 在父组件内添加一个引用到子组件。
  3. /*
    * Child component
    */
    class Child extends React.Component {
      render() {
        return (
          <div id="child">
            <h1 ref={(node) => { this.heading = node; }}>
              Child
            </h1>
          </div>
        );
      }
    }
    
    /*
     * Parent component
     */
    class Parent extends React.Component {
      componentDidMount() {
        // Access child component refs via parent component instance like this
        console.log(this.child.heading.getDOMNode());
      }
    
      render() {
        return (
          <div>
            <Child
              ref={(node) => { this.child = node; }}
            />
          </div>
        );
      }
    }
    

    演示:https://codepen.io/itsfadnis/pen/aLWVVx?editors=0011

答案 2 :(得分:15)

首先使用this.props.children访问孩子,然后每个孩子都会将ref作为属性。

答案 3 :(得分:2)

使用Ref转发,您可以将ref从父级传递到子级。

const FancyButton = React.forwardRef((props, ref) => (
  <button ref={ref} className="FancyButton">
    {props.children}
  </button>
));

// You can now get a ref directly to the DOM button:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
  1. 通过调用React.createRef创建一个React ref,并将其分配给ref变量。
  2. 通过将您的引用指定为JSX属性来将其传递给
  3. React将ref传递给forwardRef内的(props,ref)=> ...函数作为第二个参数。
  4. 通过将此ref参数指定为JSX属性,将其转发至下一个。
  5. 附加参考时,参考当前将指向DOM节点。

注意 仅当使用React.forwardRef调用定义组件时,第二个ref参数才存在。常规函数或类组件不会接收ref参数,并且ref在props中也不可用。

引用转发不限于DOM组件。您也可以将引用转发到类组件实例。

参考:React文档。

答案 4 :(得分:2)

以下是我解决动态组件问题的方法:

在父组件上,动态创建对子组件的引用,例如:

class Form extends Component {
    fieldRefs: [];

    // dynamically create the child references on mount/init
    componentWillMount = () => {
        this.fieldRefs = [];
        for(let f of this.props.children) {
            if (f && f.type.name == 'FormField') {
                f.ref = createRef();
                this.fieldRefs.push(f);
            }
        }
    }

    // used later to retrieve values of the dynamic children refs
    public getFields = () => {
        let data = {};

        for(let r of this.fieldRefs) {
            let f = r.ref.current;
            data[f.props.id] = f.field.current.value;
        }

        return data;
    }
}

子组件(即 )实现它自己的“字段”引用,从父组件引用:

class FormField extends Component {
    field = createRef();
    
    render() {
        return(
            <input ref={this.field} type={type} />
        );
    }
}

然后在您的主页,“父级的父级”组件中,您可以从引用中获取字段值:

class Page extends Component {
    form = createRef();

    onSubmit = () => {
        let fields = this.form.current.getFields();
    }

    render() {
        return (
            <Form ref={this.form}>
                <FormField id="email" type="email" autoComplete="email" label="E-mail" />
                <FormField id="password" type="password" autoComplete="password" label="Password" />

                <div class="button" onClick={this.onSubmit}>Submit</div>
            </Form>
        );
    }
}

我实现这个是因为我想从一个主要的

组件中封装所有通用的表单功能,并且能够设置主要的客户端/页面组件并设置它自己的内部组件样式的唯一方法是使用 child组件(即父 中的 项,它位于其他一些 组件中)。

所以,虽然有些人可能认为这是一种黑客行为,但它就像 React 试图阻止来自任何父级的实际“ref”一样,我认为这是一个荒谬的设计,但他们希望将其合理化。

答案 5 :(得分:1)

这里是一个示例,该示例将重点介绍使用refs(在React 16.8.6中测试)的输入:

子组件:

class Child extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  render() {
    return (<input type="text" ref={this.myRef} />);
  }
}

内部包含“子级”组件的“父级”组件:

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.childRef = React.createRef();
  }
  componentDidMount() {
    this.childRef.current.myRef.current.focus();
  }
  render() {
    return <Child ref={this.childRef} />;
  }
}

ReactDOM.render(
    <Parent />,
    document.getElementById('container')
);

具有this.props.children的Parent组件:

class Parent extends React.Component {
    constructor(props) {
        super(props);
        this.childRef = React.createRef();
    }
    componentDidMount() {
        this.childRef.current.myRef.current.focus();
    }
    render() {
        const ChildComponentWithRef = React.forwardRef((props, ref) =>
            React.cloneElement(this.props.children, {
                ...props,
                ref
            })
        );
        return <ChildComponentWithRef ref={this.childRef} />
    }
}

ReactDOM.render(
    <Parent>
        <Child />
    </Parent>,
    document.getElementById('container')
);

答案 6 :(得分:0)

我认为本指南对其进行了很好的解释https://github.com/yannickcr/eslint-plugin-react/issues/678

class Field extends Component {
  const { inputRef } = this.props;
  render() {
    return (
      <input type="text" ref={inputRef} />
    )
  }
}

class MyComponent extends Component {
  componentDidMount() {
    this.inputNode.focus();
  }

  render() {
    return (
      <div>
        Hello, <Field inputRef={node => this.inputNode = node} />
      </div>
    )
  }
}
相关问题