2

I have a render function like this one:

render() { const statement = true return ( <div> { statement && <div> <p> {this.buildStuff()} </p> <p> {this.buildStuff()} </p> <p> {this.buildStuff()} </p> </div> } </div> ); } 

To avoid calling buildStuff() three times, I would like to assign it to a variable. How can I declare a variable after the line with statement &&?

A quick solution would be to do

const statement = true const stuff = statement ? buildStuff() : null; 

but this solution use two branches instead of one.

You can try this code on StackBlitz.

This what it would look like in Razor.

12
  • What's wrong with const stuff = statement ? buildStuff() : null;? Commented Jan 16, 2019 at 9:57
  • Why can't you do it before the return statement const ui = statement && this.buildStuff(); return ... // just use ui here Commented Jan 16, 2019 at 9:58
  • @hindmost why make two statements when one should be enough? Commented Jan 16, 2019 at 10:03
  • @aloisdg Then use && as @Yury Tarabanko suggested Commented Jan 16, 2019 at 10:04
  • 1
    @aloisdg You would sacrifice readability and gain nothing. Really nothing. BTW I bet Rajesh's solution is less performant than checking a boolean :). It creates an array, temp object, anonymous functions that would be gced, and adds yet another function call. Commented Jan 16, 2019 at 10:23

4 Answers 4

3

You can try something like this as well:

  • You can create a function that deals with this UI representation.
  • In this function, you can call buildStuff and have it return 3 <p> tags.
  • Then in main render, you can check your condition and render accordingly. This will make your render clean and declarative.
getBuildJSX() { const stuff = this.buildStuff(); return Array.from({ length: 3}, () => <p> { stuff }</p>); } render() { const statement = true return ( <div> { statement ? this.getBuilsJSX() : null } </div> ); } 

Try it online

Sign up to request clarification or add additional context in comments.

2 Comments

Nice idea. Since we cannot put a variable in the JSX, we use a function to wrap the logic and move the variable in it.
@aloisdg Thanks for adding a sample. Its not opening for me, but should help others
1

First solution (edit: alternative)

render() { const statement = true; const stuff = this.buildStuff(statement, 3); // jsx result looped in divs return ( <div> { statement && <div> { stuff } </div> } </div> ); } 

Alternative, memoization (caching of functions) if this is your goal:

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> ); } 

The true power of memoization however is, if you cache based on the parameter you give to buildStuff (maybe you move statement into buildstuff?). In your case I would just clean up the component and parameters in favour of readability rather than optimising something. So last alternative:

// 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> ); } 

The benefit, you can now choose to pass the result or the function itself through props, and in the downward component either call the function or simply have its results passed through.

Single answer to your question in the headline: you cant, JSX is not a templating engine like Razor.

Explanation:

// 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")); 

Either you declare a new variable with an attribute, or you simply cant, since javascript does not allow variable creation inside parameters of functions.

Comments

0

I think one of the main ideas of react is to use components to structure your code.

So one way to do it would be like this:

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> ); } 

Updated StackBlitz.

2 Comments

AFAIK, here you transform one branching into three and you are still calling this.buildStuff() three times.
This adds another level of indirection and would still call buildStuff three times
0

This answer is an answer to the problem but not a solution to the question. If you cannot declare a variable inside brackets in react (as you could do in Razor for example). Calling twice a statement can still be your best bet.

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> ); } 

At least, we call this.buildStuff() only if needed and if we do, we call it only once.

1 Comment

Check in this: const stuff = statement ? this.buildStuff() : null is redundant. stuff will only be used in truthy case. Only benefit of this would be that, for falsey value, you are not calling function at all. But having an extra check doesn't make that much sense

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.