Template Syntax
Conditional Rendering
In jsx there is no if helper by default, we need to use javascript code to conditionally render specific things.
Ember
<p>
{{if @isOldEnough "show content" "not old enough" }}
</p>
React
export default function MyComponent({ isOldEnough }) {
// a local variable may also be utilized to reduce clutter
return {isOldEnough ? <p>show content</p> : <p>not old enough</p> }
}
If block helper
The if block helper, {{#if}} {{/if}}
, can be used to conditionally render large chunks of content.
In React we can use the same method for rendering if conditions.
Ember
<div>
{{#if @authenticated}}
<p>large complex content piece</p>
{{else}}
<p>another piece rendered in the else block</p>
{{/if}}
</div>
React
export default function MyComponent({ authenticated }) {
if (authenticated) {
return (<p>large complex conent piece</p>)
} else {
return (<p>another piece rendered in the else block</p>)
}
}
However in react we can create a if block component to be comparable to the {{if}}
helper in ember.
This is not recommended since it will render the both branch components regardless of conditional value.
React
// conditional-utils.tsx
export function If({ condition: Boolean, children: JSX.Element }) {
if (condition) {
return ({children})
}
}
export function Unless({ condition: Boolean, children: JSX.Element }) {
if (!condition) {
return ({children})
}
}
// MyComponent.tsx
import { If, Unless } from './conditonal-utils';
export default function MyComponent() {
const showStatus = false;
return (<>
<If condition={showStatus}>
<p> Showing Status</p>
</If>
<Unless condition={showStatus}>
<p>No Status</p>
</Unless>
</>)
}
In both React and Ember, there is no addtional html elements rendered for components, allowing us to use nested components for complex strucutres without performance loss on page render.
Rendering lists
Since React does not include any helpers, we cannot use the {{#each}}
helper and need to create a list of items we
want using javascript, for this example we are using the .map()
method but any function that will return our elements will work.
Ember
{{#each @messages as |msg|}}
<Message @message={{msg}} />
{{/each}}
React
import Message from "./components/Message";
export default function MyComponent({ messages }) {
return (
<>
{messages.map(msg => (
<Message key={msg} message={msg} />
))}
</>
);
}
Filtering lists
Since JSX is using javascript to render our temaplates, we can use methods like .filter()
to remove unwanted items from a list.
We can also do before the return statement to make cleaner.
Ember
{{#each @messages as |msg|}}
{{#if msg.unread}}
<Message @message={{msg}} />
{{/if}}
{{/each}}
React
import Message from "./components/Message";
export default function MyComponent({ messages }) {
const messageElements = messages
.filter(x => x.unread)
.map(msg => <Message key={msg} message={msg} />);
return (<>
{messageElements}
</>);
}