J'ai une fonction de rendu comme celle-ci:
const statement = true const stuff = statement ? buildStuff() : null;
Pour éviter d'appeler buildStuff ()
trois fois, je voudrais l'assigner à une variable. Comment puis-je déclarer une variable après la ligne avec statement &&
?
Une solution rapide serait de faire
render() { const statement = true return ( <div> { statement && <div> <p> {this.buildStuff()} </p> <p> {this.buildStuff()} </p> <p> {this.buildStuff()} </p> </div> } </div> ); }
mais cette solution utilise deux branches au lieu d'une.
Vous pouvez essayer ce code sur StackBlitz .
Voici à quoi cela ressemblerait dans Razor .
p>
4 Réponses :
Je pense que l'une des principales idées de react est d'utiliser des composants pour structurer votre code.
Une façon de procéder serait donc la suivante:
render() { const statement = true; const Stuff = ({statement}) => { if (!statement) { return null; } return this.buildStuff(); } return ( <div> <p> <Stuff statement={statement} /> </p> <p> <Stuff statement={statement} /> </p> <p> <Stuff statement={statement} /> </p> </div> ); }
Mise à jour StackBlitz .
AFAIK, ici vous transformez un branchement en trois et vous appelez toujours this.buildStuff ()
trois fois.
Cela ajoute un autre niveau d'indirection et appellerait toujours buildStuff
trois fois
Vous pouvez également essayer quelque chose comme ceci:
buildStuff
et lui faire renvoyer 3 balises
. getBuildJSX() { const stuff = this.buildStuff(); return Array.from({ length: 3}, () => <p> { stuff }</p>); } render() { const statement = true return ( <div> { statement ? this.getBuilsJSX() : null } </div> ); }
Bonne idée. Comme nous ne pouvons pas mettre de variable dans le JSX, nous utilisons une fonction pour envelopper la logique et y déplacer la variable.
@aloisdg Merci d'avoir ajouté un échantillon. Ce n'est pas une ouverture pour moi, mais devrait aider les autres
Première solution (modifier: alternative)
// JSX <div id="foo">Hello world</div> // Translates into React.createElement("div", {id: "foo"}, "Hello world"); // JSX <div>{ statement && <div /> }</div> // Translates to React.createElement("div", null, statement && React.createElement("div"));
Alternative, mémorisation (mise en cache des fonctions) si tel est votre objectif:
// Stuff is a component now const Stuff = ({statement, stuff}) => { if(!statement) return null; const result = stuff(); return ( <div> <p> {result} </p> <p> {result} </p> <p> {result} </p> </div> ) } render() { return ( <div> <Stuff statement={true} stuff={this.buildStuff} /> </div> ); }
Le vrai pouvoir de la mémorisation est cependant, si vous mettez en cache en fonction du paramètre que vous donnez à buildStuff (peut-être que vous déplacez l'instruction dans buildstuff?). Dans votre cas, je nettoierais simplement le composant et les paramètres en faveur de la lisibilité plutôt que d'optimiser quelque chose. Donc dernière alternative:
const memoize = require('fast-memoize'); const memoized = memoize(this.buildStuff); ... render() { const statement = true; return ( <div> { statement && <div> <p> {memoized()} </p> <p> {memoized()} </p> <p> {memoized()} </p> </div> } </div> ); }
L'avantage, vous pouvez maintenant choisir de passer le résultat ou la fonction elle-même à travers les accessoires, et dans le composant descendant soit appeler la fonction ou simplement avoir son résultats transmis.
Réponse unique à votre question dans le titre: vous ne pouvez pas, JSX n'est pas un moteur de création de modèles comme Razor.
Explication: p>
render() { const statement = true; const stuff = this.buildStuff(statement, 3); // jsx result looped in divs return ( <div> { statement && <div> { stuff } </div> } </div> ); }
Soit vous déclarez une nouvelle variable avec un attribut, soit vous ne pouvez tout simplement pas, car javascript ne permet pas la création de variables à l'intérieur des paramètres des fonctions.
Cette réponse est une réponse au problème mais pas une solution à la question. Si vous ne pouvez pas déclarer une variable entre crochets dans react (comme vous pourriez le faire dans Razor par exemple). Appeler deux fois une instruction peut toujours être votre meilleur pari.
render() { const statement = true const stuff = statement ? this.buildStuff() : null return ( <div> { statement && <div> <p> {stuff} </p> <p> {stuff} </p> <p> {stuff} </p> </div> } </div> ); }
Au moins, nous appelons this.buildStuff ()
uniquement si nécessaire et si nous le faisons, nous l'appelons une seule fois.
Vérifiez ceci: const stuff = statement? this.buildStuff (): null
est redondant. stuff
ne sera utilisé qu'en cas de vérité. Le seul avantage de ceci serait que, pour une valeur fausse, vous n'appelez pas du tout la fonction. Mais avoir un chèque supplémentaire n'a pas beaucoup de sens
Quel est le problème avec l'instruction
const stuff =? buildStuff (): null;
?Pourquoi ne pouvez-vous pas le faire avant l'instruction de retour
const ui = statement && this.buildStuff (); return ... // utilisez simplement ui ici
@hindmost pourquoi faire deux déclarations alors qu'une seule devrait suffire?
@aloisdg Puis utilisez
&&
comme @Yury Tarabanko l'a suggéré@YuryTarabanko vous vérifiez toujours l'instruction booléenne deux fois.
Si vous vouliez vérifier la variable
statement
, vous pouvez remplacer son utilisation dans JSX parstuff
:stuff && ...
@aloisdg Vous pouvez vérifier l'interface utilisateur à la place. :) La déclaration de variable est une instruction que vous ne pouvez pas utiliser dans une expression que vous souhaitez renvoyer. Vous pouvez déclarer
let stuff;
avant et utiliser l'opérateur virgule{statement && (stuff == this.buildStuff (), ( {stuff} )} code> mais c'est moins lisible.
@hindmost je ne suis pas sûr de comprendre. Je suis nouveau pour réagir. Pourriez-vous des détails ou donner un exemple?
@YuryTarabanko n'est pas une mauvaise idée! Cela sent un peu plus une solution de contournement qu'une vraie solution mais l'idée est là. Je ne sacrifierai pas la lisibilité pour le gain de performance d'un bool (qui n'est presque rien)
@aloisdg Je ne le recommande PAS.
const stuff = statement && this.buildStuff ()
est assez bon. La fonctionbuildStuff
serait appelée 0 ou 1 fois. Vérifier queinstruction
booléenne est véridique ne coûte rien. Ne la micro-optimisez pas.@YuryTarabanko Oui bien sûr, mais si je peux l'éviter sans aucun sacrifice, je le ferai. Dans le rasoir par exemple, c'est facile à réaliser
@aloisdg Vous sacrifieriez la lisibilité et ne gagneriez rien. Vraiment rien. BTW je parie que la solution de Rajesh est moins performante que la vérification d'un booléen :). Il crée un tableau, un objet temporaire, des fonctions anonymes qui seraient gced, et ajoute encore un autre appel de fonction.