ReactJs - Создание компонента "Если"... хорошая идея?

Я прочитал в документах React, что операторы типа "если" не могут использоваться в коде JSX, из-за того, как JSX отображается в javascript, он не работает так, как можно было бы ожидать.

Но есть ли причина, по которой внедрение компонента "if" - плохая идея? Кажется, что я отлично справляюсь с моими первоначальными испытаниями и заставляет меня задаться вопросом, почему это не делается чаще?

Часть моего намерения состоит в том, чтобы позволить реагировать на развитие как можно больше, на основе разметки - с минимальным количеством javascript. Этот подход, как мне кажется, больше похож на подход, основанный на данных.

Вы можете проверить это здесь на JS Fiddle

<script type='text/javascript' src="https://unpkg.com/[email protected]/dist/JSXTransformer.js"></script>
<script type='text/javascript' src="https://unpkg.com/[email protected]/dist/react-with-addons.js"></script>

<script type="text/jsx">
/** @jsx React.DOM */
    
var If = React.createClass({
  displayName: 'If',

  render: function()
  {
    if (this.props.condition)
      return <span>{this.props.children}</span>
    return null;
  }
});

var Main = React.createClass({
    render: function() {
        return (
           <div>
             <If condition={false}>
                <div>Never showing false item</div>
             </If>
             <If condition={true}>
                <div>Showing true item</div>
             </If>
          </div>
        );
    }
});

React.renderComponent(<Main/>, document.body);
</script>

Ответ 1

Просмотрите раздел If-Else в JSX в интерактивных документах.

В JSX вы не можете выставлять выражения внутри фигурных скобок - только выражения. Если вы не знаете разницы между выражениями против операторов в JavaScript, прочитайте эту статью . Это ограничение связано с тем, что JSX помещает вызовы функций, и вы не можете использовать if-statements в качестве аргументов функции в JavaScript. Однако вы можете использовать логические операторы (&&, || и ? :) для выполнения аналогичного задания. Они являются выражениями, поэтому они могут вписываться в вызовы конструктора, генерируемые JSX, и их короткое замыкание оценивается так же, как и в операторах if.

<div>
    {(true
        ? <div>Showing true item</div>     
        : <div>Never showing false item</div>
    )}
</div>
<p>My name is {this.name || "default name"}</p>

Кроме того, React будет обрабатывать null и false как "пустой компонент", который не будет отображаться в реальном DOM (в настоящее время он использует тот же самый трюк noscript за кулисами). Это полезно, когда вам не нужна ветка "else". Подробнее см. False в JSX.

<div>
    {shouldIncludeChild ? <ChildComponent/> : false}
</div>

Что касается компонента If, о котором вы спрашивали, одна проблема заключается в том, что в его текущей форме он будет оценивать свои дочерние элементы, даже если это условие является ложным. Это может привести к ошибкам, когда тело If имеет смысл, если условие истинно:

<If condition={person !== null}>
    //This code throws an exception if this.person is null
    <div>{person.name}</div>
</If>

Вы можете обходиться с этим, если компонент if получит тело как функцию, а не как список дочерних компонентов, но более подробный:

<If condition={person !== null} body={function(){
    return <div>{person.name}</div>
}/>

Наконец, поскольку компонент If является апатридом, вам следует рассмотреть возможность использования простой функции вместо нового класса компонентов, поскольку это сделает прозрачный алгоритм "If" прозрачным для реактивации. Если вы используете компонент If, то <div> и <If><div> будут считаться несовместимыми, а React выполнит полное перерисовку вместо того, чтобы пытаться объединить новый компонент со старым.

// This custom if function is for purely illustrative purposes
// However, this idea of using callbacks to represent block of code
// is useful for defining your own control flow operators in other circumstances.
function myCustomIf(condition, onTrue, onFalse){
    onTrue  = onTrue  || function(){ return null }        
    onFalse = onFalse || function(){ return null }
    if(condition){
        return onTrue();
    }else{
        return onFalse();
    }
}

<div>    
    {myCustomIf(person !== null, function(){
         return <div>{person.name}</div>
     })}
</div>

Ответ 2

Вам не нужно ничего, кроме простого JS.

Безопасный и читаемый (но подробный)

maybeRenderPerson: function() {
    var personName = ...;
    if ( personName ) {
        return <div className="person">{personName}</div>;
    }
}

render: function() {
    return (
       <div className="component">
          {this.maybeRenderPerson()}
       </div>
    );
}

Это немного подробный, но он позволяет легко разделить вашу логику на более мелкие, сфокусированные блоки. Когда компоненты начинают становиться сложными, это наиболее читаемо.


Краткий и читаемый (но опасный)

render: function() {
    var personName = ...; // present or absent name, but never ""
    return (
       <div className="component">
          {personName && (
            <div className="person">{personName}</div>
          )}
       </div>
    );
}

Этот синтаксис может быть весьма опасным, если тестируемая переменная может быть ложными значениями, такими как 0, "" или false. В частности, с номерами вы должны немного изменить тест, если хотите, чтобы он отображал 0:

render: function() {
    var counter= ...; // number, can be 0
    return (
       <div className="component">
          {(typeof counter !== 'undefined') && (
            <div className="counter">{counter}</div>
          )}
       </div>
    );
}

Когда компоненты становятся сложными, расщепляясь на несколько меньших компонентов, а условные обозначения в коде могут помочь сохранить его читабельность:

render: function() {
    var person= ...; 
    var counter= ...; 
    return (
       <div className="component">
          {person && (
            <Person person={person}/>
          )}
          {(typeof counter !== 'undefined') && (
            <Counter value={counter}/>
          )}
       </div>
    );
}

Современный синтаксис (но слишком рано)

Обозначение do с функциональными компонентами без состояния может быть полезно для выразительности без потери читаемости. Вы можете легко разбить большой компонент на очень маленькие и сфокусированные, которые используют обозначение do:

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

Это похоже на использование шаблона модуля внутри JSX, поэтому он довольно гибкий, но с гораздо меньшим количеством шаблонов.

Чтобы включить это, вам понадобится инструментарий компиляции ES9 stage 0, а поддержка из вашей любимой среды IDE еще не существует.

Ответ 3

Вы можете делать встроенные условные обозначения, такие как

{true && (
<div>render item</div>
)}

{false && (
<div>don't render item</div>
)}

Или вы можете просто использовать var

var something;

if (true) {
something = <div>render item</div>
}

{something}

Ответ 4

Вы можете выполнять функцию самоисполнения с правильным контекстом (с помощью Вавилона)! Который я предпочитаю, потому что нет необходимости назначать переменные, и вы можете быть настолько сложными, насколько хотите (хотя вы, вероятно, не должны для удобства обслуживания):

render() {
  return (
    <div>
      <div>Hello!</div>
      {() => {
        if (this.props.isLoggedIn) {
          return <Dashboard />
        } else {
          return <SignIn />
        }
      }()}
      <div>Another Tag</div>
    </div>
  );
}

Ответ 5

Экспериментальный синтаксис ES7 do действительно хорош для этой ситуации. Если вы используете Babel, включите функцию es7.doExpressions, а затем:

render() {
  var condition = false;

  return (
    <div>
      {do {
        if (condition) {
          <span>Truthy!</span>;
        } else {
          <span>Not truthy.</span>;
        }
      }}
    </div>
  );
}

См. http://wiki.ecmascript.org/doku.php?id=strawman:do_expressions

Ответ 6

Закрытие ES7 do отлично подходит для этого:

Например, если вы используете webpack - вы можете добавить функции ES7:

Сначала установите stage-0 функции с помощью

npm install babel-preset-stage-0 -save-dev;

Затем в настройках загрузчика webpack добавьте предустановку babel stage-0:

    loaders : [
        //...
        {
            test : /\.js$/,
            loader : "babel-loader",
            exclude : /node_modules/,
            query : {
                presets : ["react", "stage-0", "es2015"]
            }
        }
    ]

Затем ваша функция рендеринга компонента может выглядеть так:

import React , { Component } from "react";

class ComponentWithIfs extends Component {

    render() {
        return (
            <div className="my-element">
                {
                    do {
                        if ( this.state.something ) {
                            <div>First Case</div>
                        } else {
                            <div>2nd Case</div>
                        }
                    }
                }
            </div>
        );
    }
}

Ответ 7

Я думаю, что ваш главный вопрос не "Могу ли я реализовать компонент If " (потому что, конечно, вы можете это сделать), а "Есть ли какая-то причина, почему реализация компонента If - плохая идея? "

Основная причина плохой идеи в том, что компонент добавляет циклы рендеринга к тому, что в противном случае было бы небольшим количеством кода в существующем компоненте. Оболочка дополнительного компонента означает, что React должен выполнить весь дополнительный цикл рендеринга для своих дочерних элементов. Это не имеет большого значения, если компонент If используется только в одном месте, но если ваше приложение изобилует ими, вы только что сделали свой интерфейс намного медленнее.

Аналогично тому, как: <div>Hi</div> более эффективен, чем <div><div>Hi</div></div>.

Ответ 8

Я думаю, что это зависит от случая. У меня просто был тот же вопрос, почему я здесь. Я просто думаю, что если компонент для рендеринга огромен, может быть полезно иметь компонент IF вместо стандартного метода условного рендеринга.

...
<IF condition={screenIs("xs")}>
       <div> Then statement</div>
       <div>other Statement</div>
       <div>and so on</div>
</IF>
...

определенно более читабельно, чем

...
{
  screenIs("xs") &&  (
     <Fragment>
         <div> Then statement</div>
         <div>other Statement</div>
         <div>and so on</div>
      </Fragment>
    )
 }
 ...

также для троичного заявления,

...
<IF.Ternary condition={screenIs("xs")}>
   <Fragment>
       <div> Then statement</div>
       <div>other then Statement</div>
       <div>and so on</div>
   </Fragment>
   <Fragment>
       <div> Else statement</div>
       <div>other Else Statement</div>
       <div>and so on</div>
   </Fragment>
 </IF.Ternary>
 ...

более читабельно, чем

...
{
  screenIs("xs")
   ? (
     <Fragment>
         <div> Then statement</div>
         <div>other Then Statement</div>
         <div>and so on</div>
      </Fragment>
    )
    : (
     <Fragment>
         <div> Else statement</div>
         <div>other Else Statement</div>
         <div>and so on</div>
      </Fragment>
    )
 }
 ...

в любом случае, чтобы сделать его более читабельным, вы можете просто определить часть условного рендеринга в некотором методе и вызвать ее в своем основном рендере

{
  ...
  renderParts = () => {
    return screenIs('xs') ? <div>XS</div> : <div>Not XS</div>
  }
  ...
  render() {
    return (
      ...
      {this.renderParts()}
      ...
    )
  }
 }

Ответ 9

Если кому-то интересно, я только что выпустил реагировать на модуль для этих целей:

var Node = require('react-if-comp');
...
React.createClass({
    render: function() {
        return (
            <div>
                <Node if={false} else={<div>Never showing false item</div>} />
                <Node if={true} then={<div>Showing true item</div>} />
            </div>
        );
    }
});

Ответ 10

Для поддерживаемого кода пропустите ненужные абстракции, такие как If, и добавьте некоторую логику управления с ранним завершением до оператора return в вашем методе render, например

import React from 'react-native';

let {
  Text
} = React;

let Main = React.createClass({
  setInitialState() {
    return { isShown: false }
  },
  render() {
    let content;
    if (this.state.isShown) {
      content = 'Showing true item'
    } else {
      return false;
    }
    return (
      <Text>{content}</Text>
    );
  }
});

Сохраняет DRY. Прочная защита.

Ответ 11

render-if - это легкая функция, которая будет отображать элемент, если условие выполнено

В качестве встроенного выражения

class MyComponent extends Component {
  render() {
    return (
      {renderIf(1 + 2 === 3)(
        <span>The universe is working</span>
      )}
    );
  }
}

Как именованная функция

class MyComponent extends Component {
  render() {
    const ifTheUniverseIsWorking = renderIf(1 + 2 === 3);
    return (
      {ifTheUniverseIsWorking(
        <span>The universe is still wroking</span>
      )}
    )
  }
}

Как составная функция

const ifEven = number => renderIf(number % 2 === 0);
const ifOdd = number => renderIf(number % 2 !== 0);

class MyComponent extends Component {
  render() {
    return (
      {ifEven(this.props.count)(
        <span>{this.props.count} is even</span>
      )}
      {ifOdd(this.props.count)(
        <span>{this.props.count} is odd</span>
      )}
    );
  }
}

Ответ 12

Для меня достаточно воспользоваться ленивой оценкой в ​​логическом выражении, если не требуется инструкция else:

render() {
    return(
        <div>
             {
                 condition &&
                     <span>Displayed if condition is true</span>
             }
        </div>
    );    
}

Или оператор ternay, если требуется другое:

render() {
    return(
        <div>
             {
                 condition ?
                     <span>Displayed if condition is true</span>
                          :
                     <span>Displayed if condition is false</span>
             }
        </div>
    );    
}

Ответ 13

Я попытался бы избежать условного рендеринга с помощью "шаблонов" вообще. В React и JSX вы можете использовать полный набор функций JavaScript для выполнения условного рендеринга:

  • если-то еще
  • тройная
  • логический &&
  • Корпус переключателя
  • перечислений

Что делает рендеринг с JSX настолько мощным. В противном случае можно было бы снова изобрести собственные языки шаблонов, которые являются библиотекой/каркасом, определенными как в Angular 1/2.