【问题标题】:React: creating and referencing dynamic component refsReact:创建和引用动态组件引用
【发布时间】:2016-03-21 15:44:22
【问题描述】:

我正在尝试跟踪任意数量的子组件。

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

这是一个简洁的例子:

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


    【解决方案1】:

    以下将引用保存到名为this.spans的数组内的每个跨度

    这是可行的,因为每个 span 都使用 addSpanRef 方法将自己添加到 refs 数组中。

    getAllNames 然后遍历所有引用的 span 并获取它们的 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);
    

    【讨论】:

      【解决方案2】:

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

      读取所有名称的一种方法是在容器上放置一个 ref,并在 childNode 跨度上读取 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

      警告:上面的代码很脏:用户可以更改 span 的内容,而无需对 DOM 更改做出反应。这是一个(非常)坏主意

      2。更清洁的解决方案

      所以你需要 state:用户可以改变 span 的内容,并且 react 需要知道它。
      因为您还需要一个包含所有(新)已编辑名称的数组,所以此状态需要驻留在容器级别。
      这是一个纯&lt;EditableSpan&gt; 组件的解决方案,每次更改名称时,它们都会在其父级上调用一个方法。

      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,因为它们不是必需的:已知所有数据都会发生反应,因此 react 不需要 refs 从 DOM 中读取。相反,它会在每次更改时读取event.target,以更新容器状态。

      你可以在这里找到full working codepen

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

      【讨论】:

      • 抱歉,我正在尝试动态提取跨度的名称out。看起来您所做的更改是关于 setting 动态跨度的。在伪代码中:对于每个跨度,获取 textContent 并将它们作为数组返回。这有助于解释我的问题吗?
      • 用 2 个解决方案更新了答案。请注意,第二个解决方案确实返回了一个包含跨度的 textContent 的数组,但没有使用 refs。 React 是并且应该是 textContent 的唯一所有者和管理者。所以没有必要(以及错误/无法管理的代码的来源)使用 refs 来获取名称。
      【解决方案3】:

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

      此外,此解决方案也适用于 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} />)}
              )
          }
      }
      

      无论如何希望这对某人有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-07-12
        • 2019-04-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多