Comment puis-je éventuellement inclure un élément dans JSX? Voici un exemple d'utilisation d'une bannière qui devrait figurer dans le composant s'il a été passé. Ce que je veux éviter, c'est d'avoir à dupliquer les balises HTML dans l'instruction if.
render: function () {
var banner;
if (this.state.banner) {
banner = <div id="banner">{this.state.banner}</div>;
} else {
banner = ?????
}
return (
<div id="page">
{banner}
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
Laissez simplement la bannière comme étant non définie et elle ne sera pas incluse.
Et ça. Définissons un simple composant If
.
var If = React.createClass({
render: function() {
if (this.props.test) {
return this.props.children;
}
else {
return false;
}
}
});
Et utilisez-le de cette façon:
render: function () {
return (
<div id="page">
<If test={this.state.banner}>
<div id="banner">{this.state.banner}</div>
</If>
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
UPDATE: Ma réponse étant de plus en plus populaire, je me sens obligé de vous avertir du danger le plus important lié à cette solution. Comme indiqué dans une autre réponse, le code contenu dans le composant <If />
est toujours exécuté, que la condition soit vraie ou fausse. Par conséquent, le exemple suivant échouera si la banner
est null
(notez l'accès de la propriété sur la deuxième ligne):
<If test={this.state.banner}>
<div id="banner">{this.state.banner.url}</div>
</If>
Vous devez faire attention lorsque vous l'utilisez. Je suggère de lire d'autres réponses pour des approches alternatives (plus sûres).
UPDATE 2: Rétrospectivement, cette approche est non seulement dangereuse, mais également extrêmement lourde. C'est un exemple typique lorsqu'un développeur (moi) essaie de transférer des modèles et des approches qu'il connaît d'un domaine à un autre mais que cela ne fonctionne pas vraiment (dans ce cas, d'autres langages de modèle).
Si vous avez besoin d'un élément conditionnel, procédez comme suit:
render: function () {
return (
<div id="page">
{this.state.banner &&
<div id="banner">{this.state.banner}</div>}
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
Si vous avez également besoin de la branche else, utilisez simplement un opérateur ternaire:
{this.state.banner ?
<div id="banner">{this.state.banner}</div> :
<div>There is no banner!</div>
}
C'est beaucoup plus court, plus élégant et plus sûr. Je l'utilise tout le temps. Le seul inconvénient est que vous ne pouvez pas créer de branche else if
aussi facilement, mais ce n’est généralement pas aussi courant.
Quoi qu'il en soit, cela est possible grâce au fonctionnement de opérateurs logiques en JavaScript. Les opérateurs logiques permettent même de petites astuces comme celle-ci:
<h3>{this.state.banner.title || 'Default banner title'}</h3>
Personnellement, je pense vraiment que les expressions ternaires apparaissent dans http://facebook.github.io/react/tips/if-else-in-JSX.html sont la manière la plus naturelle de se conformer aux normes de ReactJs.
Voir l'exemple suivant. C'est un peu brouillon au premier abord mais ça fonctionne plutôt bien.
<div id="page">
{this.state.banner ? (
<div id="banner">
<div class="another-div">
{this.state.banner}
</div>
</div>
) :
null}
<div id="other-content">
blah blah blah...
</div>
</div>
Vous pouvez aussi l'écrire comme
{ this.state.banner && <div>{...}</div> }
Si votre state.banner
est null
ou undefined
, le côté droit de la condition est ignoré.
Le composant de style If
est dangereux car le bloc de code est toujours exécuté quelle que soit la condition. Par exemple, cela provoquerait une exception NULL si banner
est null
:
//dangerous
render: function () {
return (
<div id="page">
<If test={this.state.banner}>
<img src={this.state.banner.src} />
</If>
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
Une autre option consiste à utiliser une fonction inline (particulièrement utile avec les instructions else):
render: function () {
return (
<div id="page">
{function(){
if (this.state.banner) {
return <div id="banner">{this.state.banner}</div>
}
}.call(this)}
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
Une autre option de réaction questions :
render: function () {
return (
<div id="page">
{ this.state.banner &&
<div id="banner">{this.state.banner}</div>
}
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
Cette syntaxe de test simple + convention de style de code + petits composants ciblés est pour moi l'option la plus lisible. Vous devez juste prendre soin des valeurs de fausseté telles que false
, 0
ou ""
.
render: function() {
var person= ...;
var counter= ...;
return (
<div className="component">
{person && (
<Person person={person}/>
)}
{(typeof counter !== 'undefined') && (
<Counter value={counter}/>
)}
</div>
);
}
La syntaxe de notation de l'étape 0 de l'ES7 est également très agréable et je l'utilisera définitivement lorsque mon IDE la supportera correctement:
const Users = ({users}) => (
<div>
{users.map(user =>
<User key={user.id} user={user}/>
)}
</div>
)
const UserList = ({users}) => do {
if (!users) <div>Loading</div>
else if (!users.length) <div>Empty</div>
else <Users users={users}/>
}
Plus de détails ici: ReactJs - Créer un composant "Si" ... une bonne idée?
Simple, créer une fonction.
renderBanner: function() {
if (!this.state.banner) return;
return (
<div id="banner">{this.state.banner}</div>
);
},
render: function () {
return (
<div id="page">
{this.renderBanner()}
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
C'est un modèle que je suis personnellement tout le temps. Rend le code vraiment propre et facile à comprendre. De plus, il vous permet de refactoriser Banner
dans son propre composant s'il devient trop volumineux (ou réutilisé ailleurs).
La syntaxe expérimentale ES7 do
facilite cette opération. Si vous utilisez Babel, activez la fonction es7.doExpressions
puis:
render() {
return (
<div id="banner">
{do {
if (this.state.banner) {
this.state.banner;
} else {
"Something else";
}
}}
</div>
);
}
Voir http://wiki.ecmascript.org/doku.php?id=strawman:do_expressions
Comme déjà mentionné dans les réponses, JSX vous présente deux options
Opérateur ternaire
{ this.state.price ? <div>{this.state.price}</div> : null }
Conjonction logique
{ this.state.price && <div>{this.state.price}</div> }
Cependant, ceux-ci ne fonctionnent pas pour price == 0
.
JSX rendra la fausse branche dans le premier cas et en cas de conjonction logique, rien ne sera rendu. Si la propriété peut être 0, utilisez uniquement des instructions if en dehors de votre JSX.
Ce composant fonctionne lorsque vous avez plusieurs éléments dans la branche "if":
var Display = React.createClass({
render: function() {
if (!this.props.when) {
return false;
}
return React.DOM.div(null, this.props.children);
}
});
Usage:
render: function() {
return (
<div>
<Display when={this.state.loading}>
Loading something...
<div>Elem1</div>
<div>Elem2</div>
</Display>
<Display when={!this.state.loading}>
Loaded
<div>Elem3</div>
<div>Elem4</div>
</Display>
</div>
);
},
P.s. quelqu'un pense que ces composants ne sont pas bons pour la lecture de code. Mais dans mon esprit, le langage HTML avec javascript est pire
La plupart des exemples concernent une ligne de "html" rendue de manière conditionnelle. Cela me semble lisible lorsque plusieurs lignes doivent être restituées de manière conditionnelle.
render: function() {
// This will be renered only if showContent prop is true
var content =
<div>
<p>something here</p>
<p>more here</p>
<p>and more here</p>
</div>;
return (
<div>
<h1>Some title</h1>
{this.props.showContent ? content : null}
</div>
);
}
Le premier exemple est bon car au lieu de null
, nous pouvons restituer sous forme conditionnelle un autre contenu comme {this.props.showContent ? content : otherContent}
Mais si vous avez juste besoin d'afficher/masquer du contenu, c'est encore mieux puisque les booléens, les valeurs Null et les indéfinis sont ignorés
render: function() {
return (
<div>
<h1>Some title</h1>
// This will be renered only if showContent prop is true
{this.props.showContent &&
<div>
<p>something here</p>
<p>more here</p>
<p>and more here</p>
</div>
}
</div>
);
}
J'utilise un raccourci plus explicite: Une expression de fonction immédiatement appelée (IIFE):
{(() => {
if (isEmpty(routine.queries)) {
return <Grid devices={devices} routine={routine} configure={() => this.setState({configured: true})}/>
} else if (this.state.configured) {
return <DeviceList devices={devices} routine={routine} configure={() => this.setState({configured: false})}/>
} else {
return <Grid devices={devices} routine={routine} configure={() => this.setState({configured: true})}/>
}
})()}
Il existe une autre solution, si composant pour React :
var Node = require('react-if-comp');
...
render: function() {
return (
<div id="page">
<Node if={this.state.banner}
then={<div id="banner">{this.state.banner}</div>} />
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
Il existe également une version d'une ligne vraiment propre ... {this.props.product.title || "Pas de titre" }
C'est à dire:
render: function() {
return (
<div className="title">
{ this.props.product.title || "No Title" }
</div>
);
}
Voici mon approche utilisant ES6.
import React, { Component } from 'react';
// you should use ReactDOM.render instad of React.renderComponent
import ReactDOM from 'react-dom';
class ToggleBox extends Component {
constructor(props) {
super(props);
this.state = {
// toggle box is closed initially
opened: false,
};
// http://egorsmirnov.me/2015/08/16/react-and-es6-part3.html
this.toggleBox = this.toggleBox.bind(this);
}
toggleBox() {
// check if box is currently opened
const { opened } = this.state;
this.setState({
// toggle value of `opened`
opened: !opened,
});
}
render() {
const { title, children } = this.props;
const { opened } = this.state;
return (
<div className="box">
<div className="boxTitle" onClick={this.toggleBox}>
{title}
</div>
{opened && children && (
<div class="boxContent">
{children}
</div>
)}
</div>
);
}
}
ReactDOM.render((
<ToggleBox title="Click me">
<div>Some content</div>
</ToggleBox>
), document.getElementById('app'));
Démo: http://jsfiddle.net/kb3gN/16688/
J'utilise un code comme:
{opened && <SomeElement />}
Cela rendra SomeElement
uniquement si opened
est vrai. Cela fonctionne à cause de la façon dont JavaScript résout les conditions logiques:
true && true && 2; // will output 2
true && false && 2; // will output false
true && 'some string'; // will output 'some string'
opened && <SomeElement />; // will output SomeElement if `opened` is true, will output false otherwise
Comme React
ignorera false
, je trouve que c'est un très bon moyen de restituer certains éléments sous condition.
Vous pouvez inclure conditionnellement des éléments en utilisant l'opérateur ternaire comme ceci:
render: function(){
return <div id="page">
//conditional statement
{this.state.banner ? <div id="banner">{this.state.banner}</div> : null}
<div id="other-content">
blah blah blah...
</div>
</div>
}
J'ai créé https://www.npmjs.com/package/jsx-control-statements pour que ce soit un peu plus simple, cela permet de définir les variables conditionnelles <If>
comme des balises, puis de les compiler en if Le code à l'intérieur de <If>
n'est exécuté que si la condition est vraie.
Cela aide peut-être quelqu'un qui tombe sur la question: Tous les rendus conditionnels dans React C'est un article sur les différentes options de rendu conditionnel dans React.
Principaux points à retenir du moment d'utiliser quel rendu conditionnel:
** sinon
** opérateur ternaire
** opérateur logique &&
** boîtier de commutation
** enums
** rendus conditionnels multi-niveaux/imbriqués
** COH
** composants de templates externes
J'ai fait https://github.com/ajwhite/render-if récemment pour rendre en toute sécurité les éléments uniquement si le prédicat passe.
{renderIf(1 + 1 === 2)(
<span>Hello!</span>
)}
ou
const ifUniverseIsWorking = renderIf(1 + 1 === 2);
//...
{ifUniverseIsWorking(
<span>Hello!</span>
)}
Vous pouvez utiliser une fonction et retourner le composant tout en conservant la fonction de rendu.
class App extends React.Component {
constructor (props) {
super(props);
this._renderAppBar = this._renderAppBar.bind(this);
}
render () {
return <div>
{_renderAppBar()}
<div>Content</div>
</div>
}
_renderAppBar () {
if (this.state.renderAppBar) {
return <AppBar />
}
}
}
Avec ES6, vous pouvez le faire avec un simple liner
const If = ({children, show}) => show ? children : null
"show" est un booléen et vous utilisez cette classe par
<If show={true}> Will show </If>
<If show={false}> WON'T show </div> </If>
Il existe également une technique utilisant render props pour rendre conditionnellement un composant. Son avantage est que le rendu ne sera pas évalué tant que la condition n'est pas remplie, ce qui ne pose aucun problème pour les valeurs null et undefined.
const Conditional = ({ condition, render }) => {
if (condition) {
return render();
}
return null;
};
class App extends React.Component {
constructor() {
super();
this.state = { items: null }
}
componentWillMount() {
setTimeout(() => { this.setState({ items: [1,2] }) }, 2000);
}
render() {
return (
<Conditional
condition={!!this.state.items}
render={() => (
<div>
{this.state.items.map(value => <p>{value}</p>)}
</div>
)}
/>
)
}
}
Je ne pense pas que cela a été mentionné. Cela ressemble à votre propre réponse mais je pense que c'est encore plus simple. Vous pouvez toujours renvoyer des chaînes à partir d'expressions et vous pouvez imbriquer des expressions jsx dans des expressions, ce qui permet une expression facile à lire.
render: function () {
return (
<div id="page">
{this.state.banner ? <div id="banner">{this.state.banner}</div> : ''}
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
<script src="http://dragon.ak.fbcdn.net/hphotos-ak-xpf1/t39.3284-6/10574688_1565081647062540_1607884640_n.js"></script>
<script src="http://dragon.ak.fbcdn.net/hphotos-ak-xpa1/t39.3284-6/10541015_309770302547476_509859315_n.js"></script>
<script type="text/jsx;harmony=true">void function() { "use strict";
var Hello = React.createClass({
render: function() {
return (
<div id="page">
{this.props.banner ? <div id="banner">{this.props.banner}</div> : ''}
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
});
var element = <div><Hello /><Hello banner="banner"/></div>;
React.render(element, document.body);
}()</script>
Lorsque vous ne devez restituer que si la condition passée est remplie, vous pouvez utiliser la syntaxe:
{ condition && what_to_render }
Le code de cette manière ressemblerait à ceci:
render() {
const { banner } = this.state;
return (
<div id="page">
{ banner && <div id="banner">{banner}</div> }
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
Il existe bien sûr d'autres moyens valables de le faire, tout dépend des préférences et de l'occassion. Vous pouvez en apprendre davantage sur la manière de rendre le rendu conditionnel dans React dans cet article si cela vous intéresse!
J'aime le caractère explicite des expressions de fonction appelées immédiatement (IIFE
) et de if-else
sur render callbacks
et ternary operators
.
render() {
return (
<div id="page">
{(() => (
const { banner } = this.state;
if (banner) {
return (
<div id="banner">{banner}</div>
);
}
// Default
return (
<div>???</div>
);
))()}
<div id="other-content">
blah blah blah...
</div>
</div>
);
}
Il vous suffit de vous familiariser avec la syntaxe IIFE
, {expression}
étant la syntaxe habituelle de React. À l'intérieur, considérez que vous écrivez une fonction qui s'appelle elle-même.
function() {
}()
qui doivent être enveloppés à l'intérieur des parens
(function() {
}())