Supposons que j'ai un modal dans un composant et que je veuille afficher le modal lorsque certains boutons sont cliqués:
static getDerivedStateFromProps()(nextProps) {
if(nextProps.visible && ...) {
fetch(...).then(res => {
return {
product: res.data
}
}).catch(err => {
...
})
} else return null (or just return null here without else)
}
Dans le composant modal, je veux appeler l'API pour obtenir le produit détails basés sur l'ID sélectionné comme suit:
componentWillReceiveProps(nextProps) {
if(nextProps.visible && !this.props.visible) {
fetch(...).then(res => {
this.setState({
product: res.data
})
}).catch(err => {
...
})
}
}
De React docs il dit que componentWillReceiveProps, componentWillUpdate est obsolète et que vous devriez les éviter dans le nouveau code.J'essaie donc d'utiliser static getDerivedStateFromProps ()
render(){
...
<Modal
is={this.state.productId}
visilble={this.state.visible}
/>
}
Le code ci-dessus ne fonctionne pas car fetch est asynchrone donc il retourne toujours null ou ne retourne rien, vous ne pouvez pas utiliser await ici pour attendre que l'api se résolve également, et j'ai entendu dire que getDerivedStateFromProps ne devrait pas récupération de données.
Quelle est donc la meilleure façon de résoudre le problème?
4 Réponses :
Je pense qu'il est préférable de décider d'afficher ou non le composant Modal dans le composant parent car le composant Modal devrait être un composant fonctionnel pour rendre uniquement la vue liée au modal. De cette façon, chaque fois que le composant Modal ne sera pas rendu et uniquement rendu lorsque l'indicateur visible est vrai.
{ this.state.visible &&
<Modal />
}
Dans le composant parent, vous pouvez récupérer des données dans componentDidMount si juste après le rendu initial, les données sont requises ou componentDidUpdate si après chaque mise à jour, la récupération des données est requise pour modal. Après avoir récupéré l'état de l'ensemble de données visible sur vrai.
Codage heureux !!!
J'ai mis à jour la question, le modal doit appeler l'API en fonction du productId transmis par le composant parent
Créez simplement un composant wrapper pour Modal, disons ModalContainer, appelez l'api depuis ModalContainer et lorsque les données sont récupérées (visible: true), rendez le composant Modal. Séparation des préoccupations.
Vous pouvez monter le Modal basé sur this.state.visible et commencer la récupération lorsque Modal est monté sur componentDidMount ou lorsque les accessoires changent via componentDidUpdate
// delay
const delay = () => new Promise(res => setTimeout(res, 1000));
// fake products
const products = [
{ id: 1, text: "product 1" },
{ id: 2, text: "product 2" },
{ id: 3, text: "product 3" }
];
// fake ajax call
const API = async productId => {
await delay();
return products.find(p => p.id === productId);
};
class Parent extends Component {
state = { productId: 1, visible: false };
toggleShow = () => {
this.setState(prevState => ({ visible: !prevState.visible }));
};
setProductId = productId => this.setState({ productId, visible: true });
render() {
return (
<div className="App">
<button onClick={this.toggleShow}>show or hide</button>
<button onClick={() => this.setProductId(1)}>fetch product 1</button>
<button onClick={() => this.setProductId(2)}>fetch product 2</button>
<button onClick={() => this.setProductId(3)}>fetch product 3</button>
<button onClick={() => this.setProductId(4)}>unknown product id</button>
{this.state.visible && <Modal is={this.state.productId} />}
</div>
);
}
}
class Modal extends Component {
state = { product: null, fetching: false };
componentDidMount = () => {
this.fetchProduct();
};
componentDidUpdate = prevProps => {
if (prevProps.is !== this.props.is) {
this.fetchProduct();
}
};
fetchProduct = async () => {
this.setState({ fetching: true });
const product = await API(this.props.is);
this.setState({ product, fetching: false });
};
render() {
const { product, fetching } = this.state;
if (fetching) return <h1>{`fetching product ${this.props.is}`}</h1>;
return product ? (
<div>
<h1>{`product id: ${product.id}`}</h1>
<h3>{`text: ${product.text}`}</h3>
</div>
) : (
<h1>Product not found</h1>
);
}
}
En fait, dans une autre approche, vous pouvez utiliser dans un autre purComponent
(par exemple: componentContainer ) et appelez-le simplement dans votre vue principale. et n'utilisez qu'un seul objet dans votre état d'affichage principal comme portée de données et donnez-le comme une propriété comme ce code
this.props.someFunction('what ever you want')
et dans votre conteneur de composants :
someFunction(someval){
//do some thing
}
<componentContainer data={this.state.productDetail} modalVisible={this.state.changeNumderModal} someFunction={(val)=>this.someFunction(val)}/>
dans cette méthode, vous n'avez qu'un seul modal et une portée comme données, vous pouvez appeler les fetch et d'autres fonctions dans votre main composant comme d'autres ... et si nécessaire, vous pouvez même passer une fonction en tant que propriété au conteneur modal à:
<Modal
animationType="fade"
transparent={true}
visible={this.props.modalVisible}//<<<<<<<<<
onRequestClose={() => {
}}>
//contents:
this.props.data.map(()=>//-----)
</View>
</Modal>
et l'appeler à l'intérieur de :
construcor(prop){
super(props);
this.state={
productDetail:null<<change this in data fetch
}
}
<componentContainer data={this.state.productDetail} modalVisible={this.state.changeNumderModal}/>
Supposons donc que vous ayez fait ce masquage et affichage du modal avec un clic sur le bouton, maintenant à chaque ouverture du modèle à l'intérieur de la fonction componentWillMount
class Modal extends Component {
this.state = {product:[], loader : false}
componentWillMount(){
fetch(...).then(res => {
this.setState({
product: res.data
})
}).catch(err => {
...
})
}
render(){
const {product, loader} = this.state;
return (
if (loader) return <ProductComponent data = {product}/>
else return <div> No data found </div>
);
}
}