【问题标题】:Conditionally rendering component sections in React JSX在 React JSX 中有条件地渲染组件部分
【发布时间】:2015-05-16 06:14:27
【问题描述】:

根据MDN“您还可以在每个案例中执行多个操作,用逗号分隔它们。”下面的例子有效:

var stop = false, age = 23;

age > 18 ? (
    alert("1"),
    alert("2")
) : (
    stop = true,
    alert("Sorry, you are much too young!")
);

但我似乎无法在 React 中做同样的事情,如下所示。我希望同时显示“是”和“否”按钮,但它只显示“否”按钮。

return (
  <div className="topcoat-list">
    <ul className="topcoat-list__container">
    {
      notes.map(function (note) {
        var title = note.content.substring(0, note.content.indexOf("\n"));
title = title || note.content;
        var toggleDeleteDialogs = this.state.isConfirming && note.id === notepad.selectedId;
        var disableDelete = this.state.isConfirming && note.id !== notepad.selectedId;

          return (
          <li key={note.id} onClick={this.onSelectNote.bind(null, note.id)} className="topcoat-list__item">
            {title}

            {
              toggleDeleteDialogs ?
              (
                <button key={note.id} onClick={this.deleteThisNote.bind(null, note.id)} className="half">Yes</button>,
                <button className="half" onClick={this.onCancelDelete}>No</button>
              ) : (
              <button key={note.id} onClick={this.deleteThisNote.bind(null, note.id)} className="full" disabled={disableDelete ? "disabled" : ""}>Delete Note</button>
              )
            }

          </li>

        );
      }.bind(this))
    }
    </ul>
  </div>
);

完整标记:https://jsfiddle.net/55fvpcLo/

我的语法是关闭的还是可以更优雅地完成?

【问题讨论】:

    标签: javascript reactjs conditional-statements conditional-operator react-jsx


    【解决方案1】:

    小提琴似乎不起作用,但我可以重现该行为。虽然它不会引发Adjacent JSX elements must be wrapped in an enclosing tag 错误,但我怀疑这可能是它不起作用的原因,因为相邻元素实际上是您想要做的。

    我认为最简单的解决方案是将两个元素包装在一个封闭标签中而不是括号中。

    【讨论】:

    • 成功了,谢谢。我以前也遇到过这个问题,但这次我没有想到。就像你说的,没有产生错误。
    【解决方案2】:

    你也可以返回一个 JSX 组件数组,例如

    { 
      toggleDeleteDialogs ?
      [<Button ... />, <Button ... />] :
      <Button .../> 
    }
    

    【讨论】:

    • 太好了,我很喜欢这个选项可以防止divitis。谢谢。
    【解决方案3】:

    @Adam Stone 说得对,问题在于相邻的 JSX 元素没有包含在结束标记中。

    也就是说,您要求以最优雅的方式解决问题。

    我对您的代码进行了以下更改:

    • 使用此功能选择性地隐藏 JSX 元素:

      var hideIfFalse=function(boolean){
            return boolean? {} : {display : 'none'};
       };
      

      你可以这样使用:

      <div style={hideIfFalse(toggleDeleteDialogs)} />
      
    • 将列表项的渲染逻辑分离到renderChildren方法中:

      renderChildren:function(notes,classes){
        return  notes.map(function (note) {
        //...
      
    • 制作了一个DeleteDialog 组件。它具有可重用的功能和自己的渲染逻辑,并且将其分离提高了代码的可读性:

      var DeleteDialog=React.createClass({
        render:function(){
          var classes=this.props.classes;
      
          return <div style={hideIfFalse(this.props.toggleDeleteDialogs)}>
                <button onClick={this.props.onDelete} className="half">
                  Yes
                </button>,
                <button className="half" onClick={this.props.onCancelDelete}>
                  No
                </button>
          </div>
        }
      });
      
    • 我没有接触classSet 逻辑,但不明白它应该做什么。

    Putting it all together:

       var hideIfFalse=function(boolean){
            return boolean? {} : {display : 'none'};
        };
    
        var notepad = {
          notes:
          [
              {
                  id: 1,
                  content: "Hello, world!\nBoring.\nBoring.\nBoring."
              },
              {
                  id: 2,
                  content: "React is awesome.\nSeriously, it's the greatest."
              },
              {
                  id: 3,
                  content: "Robots are pretty cool.\nRobots are awesome, until they take over."
              },
              {
                  id: 4,
                  content: "Monkeys.\nWho doesn't love monkeys?"
              }
          ],
          selectedId: 1
        };
    
        var DeleteDialog=React.createClass({
          render:function(){
            var classes=this.props.classes;
    
            return <div style={hideIfFalse(this.props.toggleDeleteDialogs)}>
                  <button onClick={this.props.onDelete} className="half">
                    Yes
                  </button>,
                  <button className="half" onClick={this.props.onCancelDelete}>
                    No
                  </button>
            </div>
          }
    
        })
    
        var NotesList = React.createClass({
          getInitialState: function() {
            return {
              isConfirming: false
            };
          },
    
          onSelectNote: function(id) {
              notepad.selectedId = id;
          },
    
          deleteThisNote: function(noteId) {
            if(this.state.isConfirming) {
              // actual delete functionality should be here
              this.setState({isConfirming: false});
            }
            else {
              this.setState({isConfirming: true});
            }
          },
    
          onCancelDelete: function() {
            this.setState({ isConfirming: false });
          },
          renderChildren:function(notes,classes){
            return  notes.map(function (note) {
                    var title = note.content.substring(0, note.content.indexOf("\n"));
                    title = title || note.content;
                    var toggleDeleteDialogs = this.state.isConfirming && note.id === notepad.selectedId;
                    var disableDelete = this.state.isConfirming && note.id !== notepad.selectedId;
                      return <li key={note.id}
                              onClick={this.onSelectNote.bind(null, note.id)} 
                              className="topcoat-list__item">
                              {title}
                                <button key={note.id} onClick={this.deleteThisNote.bind(null, note.id)} className="full" disabled={disableDelete ? "disabled" : ""}>Delete Note</button>
                                <DeleteDialog
                                toggleDeleteDialogs={toggleDeleteDialogs}
                                note={note}
                                onDelete={this.deleteThisNote.bind(null, note.id)}
                                onCancelDelete={this.onCancelDelete.bind(this)} />
                             </li>
                    }.bind(this))
          },
    
          render: function() {
            var notes = notepad.notes;
            var cx = React.addons.classSet;
            var classes = cx({
              "topcoat-button-bar__button": true,
              "full": !this.state.isConfirming,
              "half": this.state.isConfirming,
            });
    
            return (
              <div className="topcoat-list">
                <ul className="topcoat-list__container">
                  {this.renderChildren(notes,classes)}
                </ul>
              </div>
            );
          }
        });
    
        React.render(<NotesList />, document.getElementById('container'));
    

    JSFiddle:http://jsfiddle.net/55fvpcLo/2/

    【讨论】:

    • 感谢您提供出色的作曲创意。
    猜你喜欢
    • 2018-06-30
    • 2021-06-30
    • 1970-01-01
    • 1970-01-01
    • 2021-10-11
    • 2018-12-20
    • 1970-01-01
    • 2020-12-16
    • 1970-01-01
    相关资源
    最近更新 更多