【问题标题】:Getting DOM node from React child element从 React 子元素获取 DOM 节点
【发布时间】:2026-01-07 02:15:02
【问题描述】:

使用 v0.13.0 中引入的 React.findDOMNode 方法,我能够通过映射 this.props.children 来获取传递给父组件的每个子组件的 DOM 节点。

但是,如果某些子代恰好是 React 元素而不是组件(例如,其中一个子代是通过 JSX 创建的 <div>),React 会抛出一个不变的违规错误。

无论孩子是什么类,有没有办法在挂载后获取每个孩子的正确 DOM 节点?

【问题讨论】:

    标签: reactjs


    【解决方案1】:

    this.props.children 应该是 ReactElement 或 ReactElement 数组,但不能是组件。

    要获取子元素的 DOM 节点,您需要克隆它们并为它们分配一个新的 ref。

    render() {
      return (
        <div>
          {React.Children.map(this.props.children, (element, idx) => {
            return React.cloneElement(element, { ref: idx });
          })}
        </div>
      );
    }
    

    然后您可以通过this.refs[childIdx] 访问子组件,并通过ReactDOM.findDOMNode(this.refs[childIdx]) 检索它们的DOM 节点。

    【讨论】:

    • 这不会破坏分配给父级中子级的现有ref 吗?换句话说,如果您将&lt;div ref="a" /&gt; 作为您的孩子,这不会破坏对refs.a 的任何引用,因为您将其覆盖为idx
    • 确实如此。如果你想保留 refs,你应该使用callback refs{ ref: node =&gt; this.node = node; element.ref(node); }
    • 如何从高阶组件公开 ref?例如导出默认 withInputMask(withRequired(withReadOnly(withMinMax(withHidden(TextInput)))));如果我想从 withInputMask 访问 TextInput 中的 dom 元素,我将如何实现它?我已经尝试过回调引用,但它在 withInputMask 中不可用。它未定义。
    • @monkeyjumps componentDidMount() { let outtermostDomNodeOfHoc = ReactDOM.findDOMNode(this)) }
    • 请注意,this.props.children 可以包含纯文本节点(就像我在设计一个可以包裹在任何有效 jsx 周围的灵活 &lt;Tooltip&gt; 组件时有时那样)。这将导致React.cloneElement(element) 出现错误。因此,值得检查React.isValidElement(element) 和/或typeof element === 'string'
    【解决方案2】:

    如果您想访问任何 DOM 元素,只需添加 ref 属性即可直接访问该元素。

    <input type="text" ref="myinput">
    

    然后你可以直接:

    componentDidMount: function() 
    {
        this.refs.myinput.select();
    
    },
    

    如果您已将ref 添加到任何元素,则它们不需要使用ReactDOM.findDOMNode()

    【讨论】:

    • 请注意,只有在向 DOM 元素添加了 ref 时才需要 findDOMNode(例如
      )。如果您在 React 组件节点上使用 ref(例如 ,则确实需要它。在第一种情况下 this.refs.myRef 是 DOM 节点,而在第二种情况下它是 React 组件实例。
    【解决方案3】:

    这可以通过使用 refs 属性来实现。

    在想要访问&lt;div&gt; 的示例中,您想要使用的是&lt;div ref="myExample"&gt;。然后您就可以使用React.findDOMNode(this.refs.myExample) 获取该DOM 节点。

    从那里获取每个子节点的正确 DOM 节点可能就像映射到 this.refs.myExample.children 一样简单(我还没有测试过),但您至少可以通过使用参考属性。

    这里是官方react documentation on refs了解更多信息。

    【讨论】:

    • 为我工作,但 api 现在是 ReactDom.findDOMNode(..)
    • 在状态中设置组件的反模式路径下的优秀解决方案(如果你有这个解决方案是不执行此模式并通过有状态变量有条件地呈现它)
    【解决方案4】:

    您可以使用新的React ref api 来做到这一点。

    function ChildComponent({ childRef }) {
      return <div ref={childRef} />;
    }
    
    class Parent extends React.Component {
      myRef = React.createRef();
    
      get doSomethingWithChildRef() {
        console.log(this.myRef); // Will access child DOM node.
      }
    
      render() {
        return <ChildComponent childRef={this.myRef} />;
      }
    }
    

    【讨论】:

    • 这是截至 2018 年 11 月的最新答案。也是最简单的。
    • 你如何适应未知数量的children
    【解决方案5】:

    另一个答案中提到的React.findDOMNode(this.refs.myExample) 已被弃用。

    改用'react-dom'中的ReactDOM.findDOMNode

    import ReactDOM from 'react-dom'
    let myExample = ReactDOM.findDOMNode(this.refs.myExample)
    

    【讨论】:

      【解决方案6】:

      我找到了一种使用新回调引用的简单方法。您可以将回调作为道具传递给子组件。像这样:

      class Container extends React.Component {
        constructor(props) {
          super(props)
          this.setRef = this.setRef.bind(this)
        }
      
        setRef(node) {
          this.childRef = node
        }
      
        render() {
          return <Child setRef={ this.setRef }/>
        }
      }
      
      const Child = ({ setRef }) => (
          <div ref={ setRef }>
          </div>
      )
      

      这是一个使用模态执行此操作的示例:

      class Container extends React.Component {
        constructor(props) {
          super(props)
          this.state = {
            modalOpen: false
          }
          this.open = this.open.bind(this)
          this.close = this.close.bind(this)
          this.setModal = this.setModal.bind(this)
        }
      
        open() {
          this.setState({ open: true })
        }
      
        close(event) {
          if (!this.modal.contains(event.target)) {
            this.setState({ open: false })
          }
        }
      
        setModal(node) {
          this.modal = node
        }
      
        render() {
          let { modalOpen } = this.state
          return (
            <div>
              <button onClick={ this.open }>Open</button>
              {
                modalOpen ? <Modal close={ this.close } setModal={ this.setModal }/> : null
              }
            </div>
          )
        }
      }
      
      const Modal = ({ close, setModal }) => (
        <div className='modal' onClick={ close }>
          <div className='modal-window' ref={ setModal }>
          </div>
        </div>
      )
      

      【讨论】:

      • 这真的很漂亮。我环顾了一下如何做到这一点。它很简单,就像一个魅力,不涉及使用 hacky React.findDOMNode 业务。
      • 关于你的编辑建议,只有在你使用 ES7 时才有效,我还没有配置 webpack。
      • 这样使用旧语法的人仍然能够找出这个答案。
      • True 并且那些使用它的人会希望看到它。 (对于上下文:我建议使用箭头函数来绑定 this 而不是在构造函数中进行绑定。)作为后续,我确实找到了另一种访问子引用的方法,我在下面记录为解决方案.