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?
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.
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
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
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>
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