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

IT技术 javascript reactjs
2021-04-18 22:57:47

我在 React 文档中读到“if”类​​型语句不能在 JSX 代码中使用,因为 JSX 呈现为 javascript 的方式,它不会像人们预期的那样工作。

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

我的部分目的是让 React 开发尽可能多地基于标记 - 使用尽可能少的 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>

运行上述结果:

显示真实项目

6个回答

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

在 JSX 中,您不能将语句放在花括号中——只有表达式。如果您不知道 JavaScript 中表达式与语句之间的区别,请阅读这篇文章此限制是因为 JSX 将糖化为函数调用,并且您不能将 if 语句用作 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 会将nullfalse视为不会在真实 DOM 中呈现的“空组件”(目前它在幕后使用相同的 noscript 技巧)。当您不想要“else”分支时,这很有用。有关详细信息,请参阅JSX 中的 False

<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”对 React 的协调算法透明。如果您使用 If 组件,则 a<div>和 a<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>
但是,如果您使用的是 redux,则可以让您的父组件不知道您在连接 redux 中的 If 组件时正在检查的条件,以创建一些容器。因此,您可以通过将状态映射到测试condition属性来基于 If 容器创建容器 AppWasLoaded 在这种情况下,拥有 If 并使用它来创建更具体的容器不是一个好主意吗?
2021-05-29 22:57:47
但这几乎没有回答这个问题。
2021-05-31 22:57:47
“粗箭头”函数语法使 myCustomIf 更易于使用,但我宁愿只使用内置函数?:
2021-06-03 22:57:47
你可以用 ES2015 做到这一点:gist.github.com/Ginhing/58305312a75f7f6d6165bb583ecc94ba
2021-06-13 22:57:47

除了普通的 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 中使用module模式,所以它非常灵活,但样板文件少得多。

要启用此功能,您需要 ES7 阶段 0 编译工具,并且您最喜欢的 IDE 可能尚不提供支持。

我同意这绝对是好的和干净的......并且添加更多功能可以提高可读性并有助于调用堆栈跟踪和转储!
2021-05-23 22:57:47
那个 ES7 例子真的很酷!通过删除do添加三个return语句,您可以在 ES6 中使用相同的模式
2021-05-26 22:57:47
迄今为止我读过的最准确的答案,因为它非常地道。好主意。
2021-05-28 22:57:47
我发现这种方式对于除最简单的条件检查之外的任何事情都是理想的,并且在许多不同的 React 组件之间进行选择时非常有用(即实现 switch 语句)。
2021-06-01 22:57:47

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

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

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

或者你可以只使用一个 var

var something;

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

{something}

您也可以使用正确的上下文执行自动执行功能(尽管在 Babel 的帮助下)!我更喜欢这样做,因为不需要分配变量,而且您可以随心所欲地复杂化(尽管为了可维护性,您可能不应该这样做):

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

实验性 ES7do语法非常适合这种情况。如果您使用 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