How does one select all child components (not DOM elements) used in a Reactjs component template?

久未见 提交于 2019-12-10 20:58:47

问题


I have a situation where I have two elements that are tied together, with a Board that non-negotiably always consists of 4 subdivision panels:

var BoardPanel = React.createClass({
  getInitialState: function() {
    return { someval: '' };
  }, 
  render: function() {
    <div>{this.state.someval}</div>
  },
  doSomething: function(v) {
    setState({ someval: v });
  }
});

var BoardLayout = React.createClass({
  render: function() {
    <div>
      <h1>{this.props.label{</h1>
      <div ref="panels">
        <BoardPanel />
        <BoardPanel />
        <BoardPanel />
        <BoardPanel />
      </div>
    </div>
  }
});

The BoardLayout should be able to uniformly tell each BoardPanel to call panel API functions, so I would like to do the React.js equivalent of:

this.querySelectorAll("BoardPanel")
    .array()
    .forEach(function(panel, idx) {
       panel.doSomething(idx);
    });

Note that I expressly do not want to access the DOM nodes here, I want to access the React-defined virtual elements, call functions on that, and never ever touch the actual browser-used DOM.

I had a look at the React.children utility functions, but these are fairly useless because there is no way to specify which children I want, and this.props.children is going to give me two div elements, since the BoardPanel elements live "deep" inside the template.

(I'm also fairly averse to adding ref="..." with throwaway identifiers for each BoardPanel, because there shouldn't be any need to do this, given that this is well formatted, structured markup. It's a possible workaround, but seems about as sensible as slapping ids on every element in an HTML file instead of relying on query selectors)

I could dynamically generate them by not actually having them in the template at all and adding them using React.create(BoardPanel) in BoardLayout.getInitialState but that would turn the immediately insightful template structure into an opaque placeholder, which is also a thing I'd rather not do.

Can I, in BoardLayout.componentDidMount or the like, somehow get the array of BoardPanel components used, so that I can directly instruct those components to do things? If so, how?


回答1:


If you need to do this (you probably don't), you need to use refs.

function refsToArray(ctx, prefix){
  var results = [];
  for (var i=0;;i++){
    var ref = ctx.refs[prefix + '-' + String(i)];
    if (ref) results.push(ref);
    else return results;
  }
}

var BoardLayout = React.createClass({
  var makeRef = function(){ return 'BoardPanel-'+(_refi++); }, _refi=0;
  render: function() {
    <div>
      <h1>{this.props.label{</h1>
      <div ref="panels">
        <BoardPanel ref={makeRef()} />
        <BoardPanel ref={makeRef()} />
        <BoardPanel ref={makeRef()} />
        <BoardPanel ref={makeRef()} />
      </div>
    </div>
  }
});

And then you would do refsToArray(this, 'BoardPanel') to get an array of refs.

But like I said, there's probably a better solution but you didn't indicate what you're actually trying to do.



来源:https://stackoverflow.com/questions/27555667/how-does-one-select-all-child-components-not-dom-elements-used-in-a-reactjs-co

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!