import React, { Component } from "react";
import FormUpdate from "../components/formUpdate";
import { fetchClothingItem, updateClothingItem } from "../actions/crud";
export default class Update extends Component {
constructor(props) {
super(props);
this.state = {
updateClothingItem: {}
};
}
componentWillMount() {
fetchClothingItem(this.props.match.params.postId)
.then(data => {
this.setState(state => {
state.updateClothingItem = data;
return state;
});
console.log("data", data);
//HERE IT IS RETURNING EXPECTED DATA
console.log("this.state.updateClothingItem",this.state.updateClothingItem)
})
.catch(err => {
console.error("err", err);
});
}
handleSubmit(data) {
//HERE IT IS THROWING:
> "TypeError: Cannot read property 'state' of undefined"
console.log("this.state.updateClothingItem", this.state.updateClothingItem);
updateClothingItem(this.state.updateClothingItem.id, data); this.props.router.Push("/update");
}
render() {
return (
<div>
<FormUpdate
//onSubmit={this.handleSubmit.bind(this)}
id={this.state.updateClothingItem.id}
name={this.state.updateClothingItem.name}
sleeveLength={this.state.updateClothingItem.sleeveLength}
fabricWeight={this.state.updateClothingItem.fabricWeight}
mood={this.state.updateClothingItem.body}
color={this.state.updateClothingItem.color}
/>
<button
type="submit"
onClick={this.handleSubmit}
className="addItemButton"
>
Button
</button>
</div>
);
}
}
Il y a quelques choses qui sont techniquement incorrectes en termes d'implémentation du code React.
Premièrement, Avec le style d'écriture ES6 d'une classe, toute fonction devant accéder aux propriétés de la classe doit être explicitement binded
. Dans votre cas, vous devez lier la fonction handleSubmit à l'aide de arrow function
of ou binding in constructor
.
Voir cette réponse pour plus de détails: Pourquoi et quand avons-nous besoin de lier des fonctions et des gestionnaires d'événements dans React?
Deuxièmement: Votre demande asynchrone est configurée dans la fonction composantWillMount et, dans la réponse de réussite de celle-ci, vous définissez l'état. Toutefois, l'utilisation de setState
dans componentWillMount
étant déclenchée après le rendu du composant, vous devez toujours effectuer une vérification non définie. Vous devriez plutôt utiliser la fonction componentDidMount
lifecycle pour les demandes asynchrones.
Cochez cette réponse pour savoir si vous devez avoirAJAX une requête dans componentDidMount
ou componentWillMount
Troisième: setState est asynchrone et par conséquent, la consignation des valeurs d'état après la fonction setState n'entraînera pas l'affichage de la sortie correcte. Utilisez le setState callback
à la place.
Voir ces réponses pour plus de détails:
l'appel de setState ne mute pas immédiatement
Quand utiliser le rappel React setState
Code:
export default class Update extends Component {
constructor(props) {
super(props);
this.state = {
updateClothingItem: {}
};
}
componentDidMount() {
fetchClothingItem(this.props.match.params.postId)
.then(data => {
this.setState(state => {
state.updateClothingItem = data;
return state;
});
console.log("data", data);
//HERE IT IS RETURNING EXPECTED DATA
console.log("this.state.updateClothingItem",this.state.updateClothingItem)
}) // this statement will not show you correct result since setState is async
.catch(err => {
console.error("err", err);
});
}
handleSubmit = (data) => { . // binding using arrow function here
console.log("this.state.updateClothingItem", this.state.updateClothingItem);
updateClothingItem(this.state.updateClothingItem.id, data); this.props.router.Push("/update");
}
render() {
return (
<div>
<FormUpdate
//onSubmit={this.handleSubmit.bind(this)}
id={this.state.updateClothingItem.id}
name={this.state.updateClothingItem.name}
sleeveLength={this.state.updateClothingItem.sleeveLength}
fabricWeight={this.state.updateClothingItem.fabricWeight}
mood={this.state.updateClothingItem.body}
color={this.state.updateClothingItem.color}
/>
<button
type="submit"
onClick={this.handleSubmit}
className="addItemButton"
>
Button
</button>
</div>
);
}
}
Vous avez oublié de lier votre fonction handleSubmit
à la classe. Vous pouvez soit utiliser la fonction flèche pour définir la fonction.
handleSubmit=(data) =>{
...
}
Ou vous pouvez lier la fonction dans votre constructeur.
constructor(props) {
super(props);
this.state = {
updateClothingItem: {}
};
this.handleSubmit= this.handleSubmit.bind(this,data);
}
il n'y a pas encore d'état constructeur
si vous voulez définir l'état dans le constructeur, vous pouvez le faire comme ceci
class SomeComponent extends Component {
constructor(props){
super(props)
this.state = { ... }
}
}
ou même comme ça
class SomeComponent extends Component {
state = { }
}
mais dans ce cas, babel doit être correctement configuré