Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React - passing ref to sibling

I need to have 2 sibling components, and 1 of them has to have a reference to another - is that possible?

I tried this:

<button ref="btn">ok</button>
<PopupComponent triggerButton={this.refs.btn} />

And even this

<button ref="btn">ok</button>
<PopupComponent getTriggerButton={() => this.refs.btn} />

But I get undefined in both situations. Any ideas?

Note: a parent component will not work for me, because I need to have multiple sets of those, like

<button />
<PopupComponent />
<button />
<PopupComponent />
<button />
<PopupComponent />

NOT like this:

<div>
  <button />
  <PopupComponent />
</div>
<div>
  <button />
  <PopupComponent />
</div>
<div>
  <button />
  <PopupComponent />
</div>
like image 833
Ziarno Avatar asked Mar 22 '16 18:03

Ziarno


2 Answers

Think this question is best answered by the docs:

If you have not programmed several apps with React, your first inclination is usually going to be to try to use refs to "make things happen" in your app. If this is the case, take a moment and think more critically about where state should be owned in the component hierarchy. Often, it becomes clear that the proper place to "own" that state is at a higher level in the hierarchy. Placing the state there often eliminates any desire to use refs to "make things happen" – instead, the data flow will usually accomplish your goal.

Not sure exactly what you are trying to do, but my hunch is a parent component and passing props is what you really want here.

like image 141
Mark McKelvy Avatar answered Sep 17 '22 21:09

Mark McKelvy


I completely agree with the quote Mark McKelvy has provided. What you are trying to achieve is considered an anti-pattern in React.

I'll add that creating a parent component doesn't necessarily means it has to be a direct parent, you can create a parent component further up the chain, in which you can render an array of all your children components together, having the logic to coordinate between all the children (or pairs of children according to your example) sit inside your parent.

I created a rough example of the concept which should do the trick:

class A extends React.Component {
    onClick(key) {
        alert(this.refs[key].refs.main.innerText);
    }

    render() {
        var children = [];
        for (var i = 0; i < 5; i++)
            children.push.apply(children, this.renderPair(i));

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

    renderPair(key) {
        return [
            <B ref={'B' + key} key={'B' + key} onClick={this.onClick.bind(this, 'C' + key)}/>,
            <C ref={'C' + key} key={'C' + key} onClick={this.onClick.bind(this, 'B' + key)}/>
        ];
    }
}

class B extends React.Component {
    render() {
        return <p ref="main" onClick={this.props.onClick}>B</p>;
    }
}

class C extends React.Component {
    render() {
        return <p ref="main" onClick={this.props.onClick}>C</p>;
    }
}


React.render(<A/>, document.getElementById('container'));

And any state you need to save for all your children, you do in the common parent. I really hope this helps.

like image 44
iMoses Avatar answered Sep 19 '22 21:09

iMoses