首页 > 解决方案 > 如何在 React 包装器组件中访问子节点的 DOMNodes/refs?

问题描述

class List extends Component {
   <DoSomethingToList>
    {this.props.list.map(item => <Item key={item} ref={item} />}
   </DoSomethingToList>
}

class DoSomethingToList extends Component {

  componentDidUpdate(prevProps) {
     // I want to access refs here
     let refs = this.refs
     // refs === {} ------>   Why is this happening?
  }
   render() {
     <div>
       {this.props.children}
     </div>
   }  

}

我希望能够在包装器组件的生命周期方法中将子代作为引用访问。这样我就可以跟踪以前的动画 domNodes 实例。但是每当我访问 refs 时,它们都会作为一个空对象返回。在生命周期方法中访问 refs 的 React 友好方式是什么?

标签: javascriptreactjsvirtual-domreact-lifecycle

解决方案


父/容器组件 ( DoSomethingToList) 应该跟踪 refs。

const List = ({list}) => (
    <DoSomethingToList>
    {ctx => (
        list.map((item) => <Item key={item} ref={ctx.refs[item]} />)
    )}
    </DoSomethingToList>
)

class DoSomethingToList extends Component {
    state = {refs: []};

    componentDidUpdate(prevProps, prevState) {
        let refs = prevState.refs;
        // do something with refs...
    }

    render() {
      <div>
          {this.props.children(this.state)}
      </div>
    }  
}

ref老实说,我是一个不好的做法,因为 React 不知道每次更改是否持有任何元素状态。

所以我建议公开一个子组件可以调用的回调,让父级知道更改回父级。

const List = ({list}) => (
    <DoSomethingToList>
    {ctx => (
        list.map((item) => 
            <Item key={item} value={ctx.values[item]} onUpdate={ctx.updateValue} />)
    )}
    </DoSomethingToList>
)

class DoSomethingToList extends Component {
    state = { 
        values: [],
        updateValue: this.updateValue
    };

    updateValue = (value, i) => {
        const {values} = prevState;
        const newValues = {...values};
        newValues[i] = value;
        this.setState({values: newValues});
    }

    componentDidUpdate(prevProps, prevState) {
        const {values} = prevState;
        // do something with values...
    }
    render() {
    <div>
        {this.props.children(this.state)}
    </div>
    }  
}

推荐阅读