J'écris un script qui déplace la liste déroulante en dessous ou au-dessus de l'entrée en fonction de la hauteur de la liste déroulante et de la position de l'entrée sur l'écran. Je souhaite également définir le modificateur sur la liste déroulante en fonction de sa direction. Mais utiliser à l' setState
intérieur de componentDidUpdate
crée une boucle infinie (ce qui est évident)
J'ai trouvé une solution en utilisant getDOMNode
et en définissant le nom de classe directement sur la liste déroulante, mais je pense qu'il devrait y avoir une meilleure solution en utilisant les outils React. Quelqu'un peut-il m'aider?
Voici une partie du code de travail avec getDOMNode
(une logique de positionnement un peu négligée pour simplifier le code)
let SearchDropdown = React.createClass({
componentDidUpdate(params) {
let el = this.getDOMNode();
el.classList.remove('dropDown-top');
if(needToMoveOnTop(el)) {
el.top = newTopValue;
el.right = newRightValue;
el.classList.add('dropDown-top');
}
},
render() {
let dataFeed = this.props.dataFeed;
return (
<DropDown >
{dataFeed.map((data, i) => {
return (<DropDownRow key={response.symbol} data={data}/>);
})}
</DropDown>
);
}
});
et voici le code avec setstate (qui crée une boucle infinie)
let SearchDropdown = React.createClass({
getInitialState() {
return {
top: false
};
},
componentDidUpdate(params) {
let el = this.getDOMNode();
if (this.state.top) {
this.setState({top: false});
}
if(needToMoveOnTop(el)) {
el.top = newTopValue;
el.right = newRightValue;
if (!this.state.top) {
this.setState({top: true});
}
}
},
render() {
let dataFeed = this.props.dataFeed;
let class = cx({'dropDown-top' : this.state.top});
return (
<DropDown className={class} >
{dataFeed.map((data, i) => {
return (<DropDownRow key={response.symbol} data={data}/>);
})}
</DropDown>
);
}
});
la source
setState
cela déclenchera toujours un nouveau rendu. Plutôt que de vérifierstate.top
et d'appelersetState
plusieurs fois, suivez simplement ce que vous voulezstate.top
être dans une variable locale, puis une fois à la fin de l'componentDidUpdate
appelsetState
uniquement si votre variable locale ne correspond passtate.top
. Dans l'état actuel des choses, vous réinitialisez immédiatementstate.top
après le premier rendu, ce qui vous place dans la boucle infinie.componentDidUpdate
dans ce violon .componentShouldUpdate
?Réponses:
Vous pouvez utiliser à l'
setState
intérieurcomponentDidUpdate
. Le problème est que d'une manière ou d'une autre, vous créez une boucle infinie car il n'y a pas de condition de rupture.Sur la base du fait que vous avez besoin de valeurs fournies par le navigateur une fois le composant rendu, je pense que votre approche de l'utilisation
componentDidUpdate
est correcte, elle a juste besoin d'une meilleure gestion de la condition qui déclenche lesetState
.la source
componentDidUpdate
et peut simplement être ajouté au besoin à larender
place.La
componentDidUpdate
signature estvoid::componentDidUpdate(previousProps, previousState)
. Avec cela, vous pourrez tester quels accessoires / états sont sales et appeler ensetState
conséquence.Exemple:
la source
componentDidMount
n'a pas d'arguments et n'est appelé que lorsque le composant est créé, il ne peut donc pas être utilisé dans le but décrit.componentDidMount
, alors quand j'ai écrit la réponse, le célèbre nom est tombé en cascade 😮 Encore une fois, merci et grand rattrapage!componentDidUpdate(prevProps, prevState) { if ( prevState.x!== this.state.x) { //Do Something } }
Si vous utilisez à l'
setState
intérieur,componentDidUpdate
il met à jour le composant, ce qui entraîne un appelcomponentDidUpdate
auquel il est ensuite appelé àsetState
nouveau, ce qui entraîne la boucle infinie. Vous devez appeler conditionnellementsetState
et vous assurer que la condition violant l'appel se produira éventuellement, par exemple:Si vous ne mettez à jour le composant qu'en lui envoyant des accessoires (il n'est pas mis à jour par setState, à l'exception du cas à l'intérieur de componentDidUpdate), vous pouvez appeler
setState
insidecomponentWillReceiveProps
au lieu decomponentDidUpdate
.la source
getDerivedStateFromProps
.Cet exemple vous aidera à comprendre les hooks de cycle de vie React .
Vous pouvez
setState
dansgetDerivedStateFromProps
method iestatic
et déclencher la méthode après le changement d'accessoirescomponentDidUpdate
.Dans
componentDidUpdate
vous obtiendrez le 3ème paramètre qui revient degetSnapshotBeforeUpdate
.Vous pouvez vérifier ce lien codesandbox
la source
Je dirais que vous devez vérifier si l'état a déjà la même valeur que vous essayez de définir. Si c'est le même, il est inutile de redéfinir l'état pour la même valeur.
Assurez-vous de définir votre état comme ceci:
la source
J'ai eu un problème similaire où je dois centrer l'info-bulle. React setState dans componentDidUpdate m'a mis en boucle infinie, j'ai essayé la condition que cela fonctionnait. Mais j'ai trouvé que l'utilisation dans le rappel de référence m'a donné une solution plus simple et propre, si vous utilisez la fonction en ligne pour le rappel de référence, vous serez confronté au problème nul pour chaque mise à jour de composant. Utilisez donc la référence de fonction dans le rappel de référence et définissez-y l'état, ce qui lancera le nouveau rendu
la source