Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Array of references. #1899

Closed
Nutelac opened this issue Jul 21, 2014 · 14 comments
Closed

Array of references. #1899

Nutelac opened this issue Jul 21, 2014 · 14 comments

Comments

@Nutelac
Copy link

Nutelac commented Jul 21, 2014

E.g, when I generate list of buttons, I want to assign every button to same array, which is accessible through this.refs. After that, I can perform operation on every button easily. Something like square bracket syntax <input type="text" name="input[]" /> in html.

var ButtonList = React.createClass({
    render: function() {
        return (
            {this.props.buttons.map(function(button) {
                return <MyButton ref="buttons[]" onClick={this.handleClick} label={button.label} />;
            })}
        );
    },
    handleClick: function() {
        this.refs.buttons.forEach(function(button) {
            // perform operation on button
        });
    }
});
@chenglou
Copy link
Contributor

It's not currently possible, though you could do ref={'button' + i}, then access it through this.refs['button' + i].

@bjbrewster
Copy link

👍

As well as giving each ref a unique name as @chenglou said, you can access all of the components refs with something like _.each(this.refs, function(item, name) { if (item.doSomething) item.doSomething(); }); if trying to call a method on each, or perhaps check if name begins with 'button' etc. I agree an array of references would also be useful though. We were just wishing for this too.

@sophiebits
Copy link
Collaborator

This will likely be more possible after #1373.

@zpao
Copy link
Member

zpao commented Jul 26, 2014

Going to close out to try open issues down (even if we're currently failing). Let's make it an explicit goal/non-goal of #1373.

@zpao zpao closed this as completed Jul 26, 2014
@arcanis
Copy link
Contributor

arcanis commented Mar 2, 2016

@spicyj @zpao is it now possible, since #1373 has been closed? For example, how to support an array that may have a fluctuating number of elements?

@jimfb
Copy link
Contributor

jimfb commented Mar 2, 2016

@arcanis Yes, it is possible, setup a callback ref and save the ref to an array. For more info, check out the docs (https://facebook.github.io/react/docs/more-about-refs.html#the-ref-callback-attribute) or ask a usage question on stack overflow :).

@arcanis
Copy link
Contributor

arcanis commented Mar 2, 2016

@jimfb I thought of that, but what if the number of elements shrinks? When should the extraneous elements be removed? And I asked here because it will be the first place people will find ("react array of refs" on Google) :)

@jimfb
Copy link
Contributor

jimfb commented Mar 2, 2016

@arcanis We use github issues to track bugs in the React core, and explicitly send usage questions to StackOverflow. We encourage cross-linking, so feel free to post a link to you SO question so future travelers can go to the same place.

To answer your question of when elements should be removed, the answer is "when the callback ref fires a null". You can create a closure to capture the name/identity/key in your callback function, and access/remove that value when the ref fires.

@harmony7
Copy link

harmony7 commented Jul 22, 2016

Inserting a full working example here for others' reference

class MyComponent extends React.Component {
    constructor(props) {
        super(props);
        this._nodes = new Map();
    }
    componentDidMount() {
        this.checkNodes();
    }
    componentDidUpdate() {
        this.checkNodes();
    }
    checkNodes() {
        Array.from(this._nodes.values())
            .filter(node => node != null)
            .forEach(node => {
                // do something with node
            });
    }
    render() {
        const { values } = this.props;
        return (
             <div>
                 {values.map((value, i) => (
                     <div key={i} ref={c => this._nodes.set(i, c)}>{value}</div>
                 ))}
             </div>
        )
    }
}

@Vizantiyec
Copy link

@harmony7 I use your example and it works for filtering but what if I need use simulation of currentElement.click()
like https://facebook.github.io/react/docs/refs-and-the-dom.html

@harmony7
Copy link

Like this?

(Trying to make a setup similar to https://facebook.github.io/react/docs/refs-and-the-dom.html#adding-a-ref-to-a-dom-element )

class MyComponent extends React.Component {
    constructor(props) {
        super(props);
        this._nodes = new Map();
        this._handleClick = this.handleClick.bind(this);
    }
    handleClick(e, i) {
        // Explicitly focus the text input using the raw DOM API
        const node = this._nodes.get(i);
        node.focus();
    }
    render() {
        const { values } = this.props;
        return (
             <div>
                 {values.map((value, i) => (
                     <div key={i}>
                         <input type="text" 
                             value={value}
                             ref={c => this._nodes.set(i, c)} />
                         <input type="button"
                             value="Focus the text input"
                             onClick={e => this.handleClick(e, i)} />
                     </div>
                 ))}
             </div>
        )
    }
}

Just so you know, this example is for illustration of this concept only and it does not follow some best practices, for example it is probably not the best to create the inline arrow function to handle onClick on each render.

@elie222
Copy link

elie222 commented Jan 24, 2019

The inline arrow function is fine here.

@MaksPapirovnyk
Copy link

MaksPapirovnyk commented Aug 29, 2019

for React 16+
and functional component, for class you can use this.domElements = []
const domElements = [];
arrayData.map((el) => (<button ref={(node) => domElements.push(node)} />))

@lestgabo
Copy link

@chenglou 's solution still works even today in 2019 (O_o) thanks.
I was mapping through an array to show tooltips using react-tooltip but the ref only always caught the last iteration. I solved it this way.
create array of refs: this.handleRefArray(itemData.key, itemIndex);
create ref: ref={refArray[itemIndex]}
accessed ref: afterShow={() => this.handleHideTooltipDelay(this.refs[refArray[itemIndex]])}

josephsavona pushed a commit that referenced this issue May 15, 2024
--- 

#1899 only propagated eliminated phi nodes to function expressions on the first 
iteration through blocks. However, this was buggy as later iterations could 
introduce rewrites that need to be propagated. 

[playground 
repro](https://0xeac7-forget.vercel.app/#eyJzb3VyY2UiOiJmdW5jdGlvbiBDb21wb25lbnQoKSB7XG4gIGNvbnN0IHggPSA0O1xuXG4gIGNvbnN0IGdldDQgPSAoKSA9PiB7XG4gICAgd2hpbGUgKGJhcigpKSB7XG4gICAgICBpZiAoYmF6KSB7XG4gICAgICAgIGJhcigpO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gKCkgPT4geDtcbiAgfTtcblxuICByZXR1cm4gZ2V0NDtcbn0ifQ==). 

I manually synced #1907 to check that this fix works for the VR Store codebase.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests