Comment accéder à un élément DOM dans React? Quel est l'équivalent de document.getElementById () dans React

203

Comment sélectionner certaines barres dans react.js?

Voici mon code:

var Progressbar = React.createClass({
    getInitialState: function () {
        return { completed: this.props.completed };
    },
    addPrecent: function (value) {
        this.props.completed += value;
        this.setState({ completed: this.props.completed });
    },

    render: function () {

        var completed = this.props.completed;
        if (completed < 0) { completed = 0 };


        return (...);
    }

Je souhaite utiliser ce composant React:

var App = React.createClass({
    getInitialState: function () {

        return { baction: 'Progress1' };
    },
    handleChange: function (e) {
        var value = e.target.value;
        console.log(value);
        this.setState({ baction: value });
    },
    handleClick10: function (e) {
        console.log('You clicked: ', this.state.baction);
        document.getElementById(this.state.baction).addPrecent(10);
    },
    render: function () {
        return (
            <div class="center">Progress Bars Demo
            <Progressbar completed={25} id="Progress1" />
                <h2 class="center"></h2>
                <Progressbar completed={50} id="Progress2" />
                <h2 class="center"></h2>
                <Progressbar completed={75} id="Progress3" />
                <h2 class="center"></h2>
                <span>
                    <select name='selectbar' id='selectbar' value={this.state.baction} onChange={this.handleChange}>
                        <option value="Progress1">#Progress1</option>
                        <option value="Progress2">#Progress2</option>
                        <option value="Progress3">#Progress3</option>
                    </select>
                    <input type="button" onClick={this.handleClick10} value="+10" />
                    <button>+25</button>
                    <button>-10</button>
                    <button>-25</button>
                </span>
            </div>
        )
    }
});

Je veux exécuter la fonction handleClick10 et effectuer l'opération pour ma barre de progression sélectionnée. Mais le résultat que j'obtiens est:

 You clicked:  Progress1
 TypeError: document.getElementById(...) is null

Comment puis-je sélectionner un certain élément dans react.js?

user504909
la source

Réponses:

214

Vous pouvez le faire en spécifiant le ref

EDIT: Dans react v16.8.0 avec un composant fonctionnel, vous pouvez définir une référence avec useRef. Notez que lorsque vous spécifiez une référence sur un composant fonctionnel, vous devez utiliser React.forwardRef dessus pour transmettre la référence à l'élément DOM à utiliser useImperativeHandlepour exposer certaines fonctions à partir du composant fonctionnel.

Ex:

const Child1 = React.forwardRef((props, ref) => {
    return <div ref={ref}>Child1</div> 
});

const Child2 = React.forwardRef((props, ref) => {
    const handleClick= () =>{};
    useImperativeHandle(ref,() => ({
       handleClick
    }))
    return <div>Child2</div> 
});
const App = () => {
    const child1 = useRef(null);
    const child2 = useRef(null);

    return (
        <>
           <Child1 ref={child1} />
           <Child1 ref={child1} />
        </>
    )
}

ÉDITER:

Dans React 16.3+ , utilisez React.createRef()pour créer votre référence:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  render() {
    return <div ref={this.myRef} />;
  }
}

Pour accéder à l'élément, utilisez:

const node = this.myRef.current;

DOC pour utiliser React.createRef ()


ÉDITER

Cependant, Facebook le déconseille car les références de chaîne ont des problèmes, sont considérées comme héritées et sont susceptibles d'être supprimées dans l'une des futures versions.

De la documentation:

API héritée: références de chaîne

Si vous avez travaillé avec React auparavant, vous connaissez peut-être une ancienne API où l'attribut ref est une chaîne, comme "textInput", et le nœud DOM est accessible en tant que this.refs.textInput. Nous vous le déconseillons car les références de chaîne ont certains problèmes, sont considérées comme héritées et sont susceptibles d'être supprimées dans l'une des futures versions. Si vous utilisez actuellement this.refs.textInput pour accéder aux références, nous recommandons plutôt le modèle de rappel.

Une façon recommandée pour React 16.2 et versions antérieures est d'utiliser le modèle de rappel:

<Progressbar completed={25} id="Progress1" ref={(input) => {this.Progress[0] = input }}/>

<h2 class="center"></h2>

<Progressbar completed={50} id="Progress2" ref={(input) => {this.Progress[1] = input }}/>

  <h2 class="center"></h2>

<Progressbar completed={75} id="Progress3" ref={(input) => {this.Progress[2] = input }}/>

DOC pour utiliser le rappel


Même les versions plus anciennes des références définies réagissent en utilisant une chaîne comme ci-dessous

<Progressbar completed={25} id="Progress1" ref="Progress1"/>

    <h2 class="center"></h2>

    <Progressbar completed={50} id="Progress2" ref="Progress2"/>

      <h2 class="center"></h2>

    <Progressbar completed={75} id="Progress3" ref="Progress3"/>

Pour obtenir l'élément, faites simplement

var object = this.refs.Progress1;

N'oubliez pas d'utiliser à l' thisintérieur d'un bloc fonction flèche comme:

print = () => {
  var object = this.refs.Progress1;  
}

etc...

Shubham Khatri
la source
5
Facebook déconseille cette approche. Voir ici facebook.github.io/react/docs/refs-and-the-dom.html
Dmitry
4
@dmitrymar Comme je peux le voir, la page ci-dessus est écrite pour la v15.4.2 et je suppose que ce n'était pas là plus tôt lorsque j'ai écrit la réponse. Quoi qu'il en soit, la réponse a été modifiée avec la bonne approche
Shubham Khatri
2
@MattSidor, merci pour la modification, vous m'avez fait gagner du temps :-)
Shubham Khatri
Euh, je me demande si je ne peux pas y accéder via le "this", comme si le composant dont j'avais besoin était une instance d'une autre classe? (c.-à-d. un autre composant enfant réagit au sein du composant parent)
akshay kishore
@akshaykishore Vous devez transmettre la référence en utilisant un autre nom, comme innerRef et la transmettre au composant souhaité
Shubham Khatri
37

Pour obtenir l'élément, reactvous devez utiliser refet à l'intérieur de la fonction, vous pouvez utiliser la ReactDOM.findDOMNodeméthode.

Mais ce que j'aime faire de plus c'est d'appeler l'arbitre juste à l'intérieur de l'événement

<input type="text" ref={ref => this.myTextInput = ref} />

Ceci est un bon lien pour vous aider à comprendre.

EQuimper
la source
2
C'est la bonne façon de procéder. Cela ajoute une référence à l'élément sur l'objet / classe à laquelle vous pouvez simplement utiliser this.myTextInputpour accéder.
Sam Parmenter du
1
Comment puis-je faire cela avec un élément créé dynamiquement?
Sagar Kodte
L'appel React.findDOMNodeme donnereact__WEBPACK_IMPORTED_MODULE_0___default.a.findDOMNode is not a function
James Poulose
@JamesPoulose assurez-vous que vous ne courez pas en mode strict, car react ne vous permettra pas d'utiliser React.findDOMNodeen mode strict.
Limpuls
12

Vous pouvez remplacer

document.getElementById(this.state.baction).addPrecent(10);

avec

this.refs[this.state.baction].addPrecent(10);


  <Progressbar completed={25} ref="Progress1" id="Progress1"/>
Piyush.kapoor
la source
3
Comment puis-je faire cela avec un élément créé dynamiquement?
Sagar Kodte
1

Étant donné que React utilise du code JSX pour créer un code HTML, nous ne pouvons pas référencer dom à l'aide de méthodes de régulation telles que documment.querySelector ou getElementById.

Au lieu de cela, nous pouvons utiliser le système de référence React pour accéder à Dom et le manipuler, comme indiqué dans l'exemple ci-dessous:

constructor(props){

    super(props);
    this.imageRef = React.createRef(); // create react ref
}

componentDidMount(){

    **console.log(this.imageRef)** // acessing the attributes of img tag when dom loads
}


render = (props) => {

const {urls,description} = this.props.image;
    return (

            <img
             **ref = {this.imageRef} // assign the ref of img tag here**
             src = {urls.regular} 
             alt = {description}
             />

        );

}

}

Nikhil Kamani
la source
1
Ce n'est pas vrai. Vous pouvez ajouter un identifiant à l'élément img, le récupérer à l'aide de document.getElementById et, dans la plupart des cas, cela fonctionnera correctement. Cela peut causer des problèmes / rendre votre code plus difficile à déboguer, mais react / jsx ne le rend pas possible pour que vous puissiez utiliser des méthodes Dom natives
adam tropp