web-dev-qa-db-fra.com

Comment lier correctement le rappel onChange à 'this' avec ReactJS, Redux et ES2015?

J'apprends ReactJS et Redux et je ne vois pas comment obtenir un accès à mon instance TextField tout en liant son rappel onChange à this.

(J'utilise material-ui pour cet exemple, mais je rencontrerais tout à fait le même problème sans cela)

import React, {Component} from 'react';
import { connect } from 'react-redux';
import { setDataValue } from './actions/data';
import TextField from 'material-ui/lib/text-field';
import Paper from 'material-ui/lib/paper';

export class DataInput extends Component {
    constructor(props){
        super(props);
    }

    handleTextChange() {
        this.props.setDataValue(document.getElementById('myField').value);
    }

    render(){
        return (
            <Paper style={{
                width: '300px',
                margin: '10px',
                padding: '10px'
            }}>
                <TextField 
                  id='myField'
                  defaultValue={this.props.data.value}
                  onChange={this.handleTextChange.bind(this)} />
            </Paper>
        );
    }
}

export default connect(
  (state) => ({data: state.data}),
  {setDataValue}
)(DataInput);

J'utilise une solution que je trouve laide (non réutilisable => pas très 'compatible avec les composants') en définissant une id sur mon TextField et en accédant à sa valeur avec document.getElementById('myField').value

Comment pourrais-je me débarrasser de cette id et y accéder avec quelque chose comme textFieldRef.value dans mon rappel?

J'ai essayé sans .bind(this), ce qui me permet d'accéder à mon instance TextField via this, mais je ne peux plus accéder à ma fonction this.props.setDataValue() car this n'est pas lié à mon contexte de classe.

Je vous remercie !

8
Romain Durand

Évitez d’utiliser des appels tels que document.getElementById dans un composant React. React est déjà conçu pour optimiser les appels DOM onéreux. Vous agissez ainsi contre le framework. Si vous voulez savoir comment référencer les noeuds DOM dans React, lisez le document here .

Cependant, dans cette situation, vous n'avez pas réellement besoin de références. Placer un ref (ou un ID) sur TextField ne va pas forcément au travail. Ce que vous référencez est un élément React, pas un nœud DOM.

Utilisez plutôt le callback onChange. La fonction passée à onChange est appelée avec un argument event. Vous pouvez utiliser cet argument pour obtenir la valeur d'entrée. (voir Système d'événements .)

Votre gestionnaire d'événement devrait ressembler à ceci:

handleTextChange(event) {
    this.props.setDataValue(event.target.value);
}

Et votre TextField devrait ressembler à ceci:

<TextField 
    value={this.props.data.value}
    onChange={event => this.handleTextChange(event)}
/>

Remarque: Utilisez la valeur NOT defaultValue .

19
David L. Walsh

Utiliser l'état avec Redux est un mauvais style. C'est donc un problème de conception du code. 

Redux devait être utilisé avec des composants fonctionnels et non ceux de style classique. 

Je suggère d'utiliser un composant fonctionnel et de transmettre un événement syntetic en tant que paramètre à la fonction onChange comme ceci:

const mapDispatchToProps = (dispatch) => {
return {
    onChange: (value) => {
        dispatch(changeAction(value))
    }
}

puis utilisez quelque chose comme ça à l'intérieur de l'élément:

<input onChange={ (e) => onChange(e.target.value)}

Vous pouvez également transmettre des propriétés propres aux éléments:

const mapDispatchToProps = (dispatch) => {
1
Den Roman