javascript-ReactJs-创建一个“ If”组件...一个好主意?

我在React文档中已经读到,“如果”类型语句不能在JSX代码中使用,由于JSX呈现到javascript中的方式,它无法按预期运行。

但是,有什么理由为什么实现“ if”组件是个坏主意? 从我的最初测试来看,它似乎工作正常,并且使我想知道为什么不经常这样做?

我的部分意图是让响应开发尽可能地基于标记,并且使用尽可能少的javascript。 在我看来,这种方法更像是一种“数据驱动”方法。

您可以在JS Fiddle上查看

<script type='text/javascript' src="https://unpkg.com/react@0.11.0/dist/JSXTransformer.js"></script>
<script type='text/javascript' src="https://unpkg.com/react@0.11.0/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>

运行上面的结果是:

显示真实物品

Brad Parks asked 2020-01-16T21:20:27Z
13个解决方案
61 votes

在react Docs中查看JSX中的If-Else部分。

在JSX中,您不能将语句放在大括号中,而只能放在表达式中。 如果您不了解JavaScript中表达式与语句之间的区别,请阅读本文。 此限制是因为JSX简化了函数调用,并且您不能将if语句用作JavaScript中函数的参数。 但是,您可以使用布尔运算符(<div><If><div>? :)完成类似的工作。 它们是表达式,因此可以放入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会将2705694016510810886912和<If><div>视为未在真实DOM中呈现的“空组件”(当前,它在幕后使用相同的Noscript技巧)。 当您不希望使用“ else”分支时,这很有用。 有关详细信息,请参见JSX中的False。

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

至于您所询问的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”对React的对帐算法透明。 如果使用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>
hugomg answered 2020-01-16T21:21:00Z
34 votes

您只需要普通的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>
    );
}

如果测试的变量可能是虚假的值(例如dodofalse),则此语法可能非常危险。特别是对于数字,如果要确保测试结果为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中使用模块模式,因此它非常灵活,但样板少了很多。

为此,您需要ES7阶段0编译工具,并且可能尚不存在您所喜爱的IDE的支持。

Sebastien Lorber answered 2020-01-16T21:22:01Z
16 votes

您可以像这样进行内联条件

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

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

或者你可以只使用一个变种

var something;

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

{something}
Chad Scira answered 2020-01-16T21:22:25Z
5 votes

您也可以在正确的上下文中执行自执行功能(尽管在Babel的帮助下)! 我更喜欢这种方式,因为不需要分配变量,并且您可以根据需要进行复杂设置(尽管出于可维护性考虑,您可能不应该这样做):

render() {
  return (
    <div>
      <div>Hello!</div>
      {() => {
        if (this.props.isLoggedIn) {
          return <Dashboard />
        } else {
          return <SignIn />
        }
      }()}
      <div>Another Tag</div>
    </div>
  );
}
rclai answered 2020-01-16T21:22:45Z
4 votes

对于这种情况,实验性的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]

balexand answered 2020-01-16T21:23:10Z
2 votes

ES7 stage-0封闭功能非常适合:

例如,如果您使用的是stage-0,则可以添加ES7功能:

首先使用以下命令安装stage-0功能:

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

然后在webpack加载程序设置中,添加Stage-0 babel预设:

    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>
        );
    }
}
pie6k answered 2020-01-16T21:23:47Z
2 votes

我认为这要视情况而定。 我只是有一个同样的问题,就是为什么我在这里。 我只是认为,如果要渲染的组件很大,那么使用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()}
      ...
    )
  }
 }
user3550446 answered 2020-01-16T21:24:25Z
2 votes

我认为您的主要问题不是“我是否可以实施If组件”(因为显然可以),而是“有没有理由实施If组件不是一个好主意?”

这是一个坏主意的主要原因是,添加组件的渲染周期会增加现有组件中的少量代码。 额外的组件包装器意味着React需要在其子代上运行整个额外的渲染周期。 如果仅在一个地方使用If组件,这没什么大不了的,但是如果您的应用程序杂乱无章,您的UI就会慢很多。

与方式类似:<div>Hi</div><div><div>Hi</div></div>更有效。

Ev Haus answered 2020-01-16T21:24:54Z
1 votes

如果有人感兴趣,我为此发布了一个react模块:

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>
        );
    }
});
Gordon Freeman answered 2020-01-16T21:25:14Z
0 votes

对于可维护的代码,请跳过If之类的不必要的抽象,并在render方法中的return语句之前添加一些带有提前终止的控制逻辑,例如

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

让您保持干燥。 持久的保护。

Josh Habdas answered 2020-01-16T21:25:39Z
0 votes

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>
      )}
    );
  }
}
Atticus answered 2020-01-16T21:26:11Z
0 votes

对我来说,如果不需要其他语句,就可以利用逻辑表达式中的惰性求值:

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

或三元运算符(如果需要其他):

render() {
    return(
        <div>
             {
                 condition ?
                     <span>Displayed if condition is true</span>
                          :
                     <span>Displayed if condition is false</span>
             }
        </div>
    );    
}
José Antonio Postigo answered 2020-01-16T21:26:36Z
0 votes

我会尽量避免使用“模板”进行条件渲染。 在React和JSX中,您可以使用全套JavaScript功能来进行条件渲染:

  • 如果别的
  • 三元
  • 逻辑&&
  • 开关盒
  • 枚举

这就是使JSX渲染如此强大的原因。 否则,人们可能会再次发明自己的特定于模板/库的模板语言,例如Angular 1/2。

Robin Wieruch answered 2020-01-16T21:27:22Z
translate from https://stackoverflow.com:/questions/25224793/reactjs-creating-an-if-component-a-good-idea