web-dev-qa-db-fra.com

l'entrée event.target est null dans this.setState [React.js]

Dans mon composant de réaction, j'ai une entrée de fichier: 

<input type="file" onChange={this.onFileChange.bind(this)} />` 

et ma onFileChange est:

onFileChange(e) {
  let file = e.target.files[0];
  this.setState(() => ({ file: e.target.files[0] })); //doesnt work
  // this.setState(() => ({ file })); //works
  // this.setState({ file: e.target.files[0] }); //works
}

Cette première façon de définir les états échoue avec une erreur: 

Cannot read property 'files' of null

React donne également l'avertissement suivant: 

This synthetic event is reused for performance reasons. If you're 
seeing this, you're accessing the property 'target' on a 
released/nullified synthetic event

Mais les deux dernières façons de définir l'état ne donnent pas d'erreur ni d'avertissement. Pourquoi cela arrive-t-il? 

4
S_Farsai

La fonction setState est exécutée dans un contexte asynchrone. 

Au moment où l'état est mis à jour, la référence e.target peut être ou ne pas être partie.

const file = e.target.files[0]; peut être utilisé pour "mémoriser" la valeur comme dans votre exemple.

9
Kunukn

Quelle est la raison d'appeler setState avec callback? this.setState({ file: e.target.files[0] }) devrait faire le travail.

Dans votre code, vous faites référence à un objet événement synthétique qui ne contient plus d'informations sur l'événement DOM d'origine. React réutilise les objets d'événement pour des raisons de performances.

Sinon, vous pouvez utiliser:

let file = e.target.files[0]; const files = e.target.files this.setState(() => ({ file: files[0] })); //doesnt work

2
dev-null

React utilise le pool d’événements. Pour en savoir plus, consultez la documentation ici https://reactjs.org/docs/events.html

setState est une fonction asynchrone

this.setState(() => ({ file })); // is correct
2
Eric Hasselbring

class Example extends React.Component {

  onFileChange = e => {
    let file = e.target.files[0];
    this.setState(() => ({ file: file }));
  }
  render() {
    return <input type="file" onChange={this.onFileChange} />;
  }
}

ReactDOM.render(
  <Example />,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="root">
</div>

0
Mikhail Katrin

Très simple/exemple de base pour faire la même tâche: 

class Hello extends React.Component {
    constructor(props) {
    super(props);
    this.state = {
    file: ''
    };
  }

  render() {
    return <div>
    <input type='file' onChange={(e) => {
    this.setState({file: e.target.files[0]}, () => {
        console.log('state', this.state);
    })
    }} />
    </div>;
  }
}

ReactDOM.render(
  <Hello name="World" />,
  document.getElementById('container')
);

J'ai ajouté le journal de la console lorsque l'état sera défini, il enregistrera les détails du fichier. Vous pouvez voir dans le journal lorsque vous sélectionnez un fichier que l'état inclut les données du fichier. 

Pour voir le journal de la console, vous devez cliquer avec le bouton droit de la souris sur Inspect et voir la console.

Exemple de travail de caisse ici https://jsfiddle.net/1oj3h417/2/

Faites-moi savoir si vous avez des doutes

0
thakurinbox