J'ai caché/montré des composants React en ne les rendant pas, par exemple:
render: function() {
var partial;
if (this.state.currentPage === 'home') {
partial = <Home />;
} else if (this.state.currentPage === 'bio') {
partial = <Bio />;
} else {
partial = <h1>Not found</h1>
}
return (
<div>
<div>I am a menu that stays here</div>
<a href="#/home">Home</a> <a href="#/bio">Bio</a>
{partial}
</div>
);
}
mais dites simplement que le <Bio/>
le composant a beaucoup d'état interne. Chaque fois que je recrée le composant, il perd son état interne et revient à son état d'origine.
Je sais bien sûr que je pourrais stocker les données quelque part et les transmettre via des accessoires ou simplement y accéder globalement, mais ces données n'ont pas vraiment besoin de vivre en dehors du composant. Je pourrais également masquer/afficher des composants à l'aide de CSS (display:none
), mais je préfère les masquer/afficher comme ci-dessus.
Quelle est la meilleure pratique ici?
EDIT: Peut-être une meilleure façon d'énoncer le problème est d'utiliser un exemple:
Ignorez React et supposez que vous utilisiez simplement une application de bureau qui avait une boîte de dialogue de configuration avec un composant Tab appelé A, qui a 2 onglets, nommés 1 et 2.
Supposons que l'onglet A.1 possède un champ de texte e-mail et que vous remplissiez votre adresse e-mail. Ensuite, vous cliquez sur l'onglet A.2 pendant une seconde, puis cliquez sur l'onglet A.1. Que s'est il passé? Votre adresse e-mail ne serait plus là, elle aurait été réinitialisée à rien car l'état interne n'était stocké nulle part.
L'intériorisation de l'état fonctionne comme suggéré dans l'une des réponses ci-dessous, mais uniquement pour le composant et ses enfants immédiats. Si vous aviez des composants imbriqués de manière arbitraire dans d'autres composants, par exemple, Tabs in Tabs in Tabs, la seule façon pour eux de conserver leur état interne est de l'externaliser quelque part ou d'utiliser le display:none
approche qui garde en fait tous les composants enfants à tout moment.
Il me semble simplement que ce type de données n'est pas des données dont vous voulez salir l'état de votre application ... ou même que vous devez même y penser. Il semble que les données que vous devriez pouvoir contrôler au niveau du composant parent, et choisir de conserver ou de supprimer, sans utiliser le display:none
approchez-vous et sans vous préoccuper des détails sur la façon dont il est stocké.
Une option serait de déplacer le conditionnel à l'intérieur du composant lui-même:
Bio = React.createClass({
render: function() {
if(this.props.show) {
return <p>bio comp</p>
} else {
return null;
}
}
});
<Bio show={isBioPage} />
Que ce soit ou non une "meilleure pratique" dépend probablement de la situation exacte.
Malheureusement, style={{display: 'none'}}
astuce ne fonctionne que sur l'élément DOM normal, pas React composant. Je dois encapsuler le composant à l'intérieur d'un div. Je n'ai donc pas à cascader l'état au sous-composant.
<div className="content">
<div className={this.state.curTab == 'securities' ? 'active' : ''}>
<Securities />
</div>
<div className={this.state.curTab == 'plugins' ? 'active' : ''}>
<Plugins />
</div>
</div>
On dirait la documentation officielle suggère cacher les enfants avec état avec style={{display: 'none'}}
Le problème fondamental ici est qu'en React vous n'êtes autorisé qu'à monter le composant sur son parent, ce qui n'est pas toujours le comportement souhaité. Mais comment résoudre ce problème?
Je propose la solution, adressée pour résoudre ce problème. Une définition plus détaillée du problème, src et des exemples peuvent être trouvés ici: https://github.com/fckt/react-layer-stack#rationale
Raisonnement
react
/react-dom
vient est livré avec 2 hypothèses/idées de base:
- chaque interface utilisateur est naturellement hiérarchique. C'est pourquoi nous avons l'idée de
components
qui s'enveloppentreact-dom
monte le composant enfant (physiquement) sur son nœud DOM parent par défautLe problème est que parfois la deuxième propriété n'est pas ce que vous voulez dans votre cas. Parfois, vous souhaitez monter votre composant dans un nœud DOM physique différent et maintenir en même temps une connexion logique entre le parent et l'enfant.
Un exemple canonique est un composant de type info-bulle: à un moment donné du processus de développement, vous pourriez constater que vous devez ajouter une description pour votre
UI element
: il sera rendu en calque fixe et devrait connaître ses coordonnées (qui sont queUI element
coord ou coordonnées de la souris) et en même temps, il a besoin d'informations si elle doit être affichée maintenant ou non, son contenu et un certain contexte des composants parents. Cet exemple montre que parfois la hiérarchie logique ne correspond pas à la hiérarchie DOM physique.
Jetez un oeil à https://github.com/fckt/react-layer-stack/blob/master/README.md#real-world-usage-example pour voir l'exemple concret qui est la réponse à votre question (jetez un œil à la propriété "use"):
import { Layer, LayerContext } from 'react-layer-stack'
// ... for each `object` in array of `objects`
const modalId = 'DeleteObjectConfirmation' + objects[rowIndex].id
return (
<Cell {...props}>
// the layer definition. The content will show up in the LayerStackMountPoint when `show(modalId)` be fired in LayerContext
<Layer use={[objects[rowIndex], rowIndex]} id={modalId}> {({
hideMe, // alias for `hide(modalId)`
index } // useful to know to set zIndex, for example
, e) => // access to the arguments (click event data in this example)
<Modal onClick={ hideMe } zIndex={(index + 1) * 1000}>
<ConfirmationDialog
title={ 'Delete' }
message={ "You're about to delete to " + '"' + objects[rowIndex].name + '"' }
confirmButton={ <Button type="primary">DELETE</Button> }
onConfirm={ this.handleDeleteObject.bind(this, objects[rowIndex].name, hideMe) } // hide after confirmation
close={ hideMe } />
</Modal> }
</Layer>
// this is the toggle for Layer with `id === modalId` can be defined everywhere in the components tree
<LayerContext id={ modalId }> {({showMe}) => // showMe is alias for `show(modalId)`
<div style={styles.iconOverlay} onClick={ (e) => showMe(e) }> // additional arguments can be passed (like event)
<Icon type="trash" />
</div> }
</LayerContext>
</Cell>)
// ...