React:创建和引用动态组件引用

问题描述 投票:2回答:3

我试图跟踪任意数量的子组件。

通常你会引用this.refs.refName,但在我的情况下,我需要跟踪任意数量的引用。

这是一个简洁的例子:

var NamesList = React.createClass({
  getAllNames: function() {
    // Somehow return an array of names...

    var names = [];
    this.refs.????.forEach(function (span) {
      names.push(span.textContent);
    })
  },

  render: function() {
    var names = ['jack','fred','bob','carl'];
    var spans = [];

    names.forEach(function (name) {
      spans.push(<span contentEditable={true} ref='?????'>name</span>);
    });

    return (
      <div>
        {spans}
      </div>;
    );
  }
});

ReactDOM.render(<NamesList></NamesList>, mountNode);

如果我正在接近问题,请告诉我。我希望的结果是将数据从RESTful服务传递到React组件,允许用户编辑该数据,并在需要时再次导出。我一直无法在React refs文档中找到答案。

dynamic reactjs contenteditable ref
3个回答
2
投票

以下内容保持对名为this.spans的数组内的每个span的引用

这是有效的,因为每个span使用addSpanRef方法将自身添加到refs数组。

getAllNames然后浏览所有引用的跨度并抓取他们的textContent。

如果您有子组件(而不是跨组件),则可以在这些子节点上调用方法!

var NamesList = React.createClass({

  // returns an array of names
  getAllNames() {
    return this.spans.map((span) => span.textContent);
  },

  // Add to our spans refs array
  addSpanRef (node) {
    this.spans = [...this.spans, node];
  },

  render: function() {
    this.spans = []; // create the spans refs array
    var names = ['jack','fred','bob','carl'];

    // Save a ref to "this" for the forEach loop
    var thisRef = this;
    names.forEach(function (name) {
      spans.push(<span contentEditable={true} ref={thisRef.addSpanRef}>name</span>);
    });

    return (
      <div>
        {spans}
      </div>;
    );
  }
});

ReactDOM.render(<NamesList></NamesList>, mountNode);

1
投票

1.快速而肮脏的解决方案:通过参考容器组件读取名称

读取所有名称的一种方法是在容器上放置一个引用,并在childNode span上读取textcontent。

  componentDidMount: function() {
    var elem = this.refs.container.getDOMNode();
    var nameNodes = elem.children;
    var names = [];
    for (var i=0; i<nameNodes.length; i++) {
      names.push(nameNodes[i].textContent);
    }
    console.log(names);
  },

你可以找到Working codepen of this here

警告:上面的代码是脏的:用户可以更改跨度的内容,而无需了解DOM更改。这是一个(非常)糟糕的主意。

2.清洁解决方案

因此,您将需要状态:用户可以更改跨度的内容,并做出反应以了解它。 因为您还需要一个包含所有(新)编辑名称的数组,所以此状态需要驻留在容器级别。 这是一个纯<EditableSpan>组件的解决方案,每次更改名称时都会在其父级上调用方法。

var EditableSpan = React.createClass({
  onChange: function() {
    var newContent = event.target.textContent;
    this.props.onChange(this.props.index, newContent);
  },
  render: function() {
    return <span 
             contentEditable={true} 
             onInput={this.onChange}>
      {this.props.name}</span>
  }
});

请注意,这个更干净的解决方案不再使用refs,因为它们不是必需的:已知所有数据都会做出反应,因此反应不需要refs从DOM读取。相反,它会在每次更改时读取event.target,以更新容器状态。

你可以在这里找到full working codepen

警告:对于这个解决方案,我添加了快速和脏的keys(名称)。 React需要唯一的键(而不是索引)。由于列表中的名称不能保证是唯一的,因此您可能需要另一个更智能的解决方案(ID或创建的时间戳会这样做)。


-1
投票

这可能是我找到的创建动态引用的最简单方法。

此解决方案也可以在没有任何TypeScript问题的情况下工作。

const Child = props => <input ref={refElem => setRef(props.someKey, refElem)} />

class Parent extends Component {

    setRef = (key, ref) => {
      this[key] = ref; // Once this function fires, I know about my child :)
    };

    render(){
        return (
          {myList.map(listItem => <Child someKey={listItem.key} setRef={this.setRef} />)}
        )
    }
}

无论如何希望这有助于某人。

© www.soinside.com 2019 - 2024. All rights reserved.