【问题标题】:Reduce code redundancy when conditionally loading Reactjs components在有条件地加载 Reactjs 组件时减少代码冗余
【发布时间】:2016-05-25 17:58:45
【问题描述】:

我正在尝试在类似父组件 <Block1> 中加载不同的 React 组件。

我想要实现的是,当我按下 “next” 按钮 <Button1><Component2> 必须加载到 <Block1>“next” 按钮应更改为 “previous”,但点击 “previous” <Button2> 必须加载 <Component1>

我不想使用<Block2>。如您所见,我在这里写了很多冗余代码。有没有办法只在点击按钮时更改<Block1> 中的组件?

var Block1 = React.createClass({
  render: function(){
    return(
      <div className="block">
        <Component1/>
        <Button1/>
      </div>
    )
  }
});

var Component1 = React.createClass({
  render: function(){
    return(
      <p className = "component1">This is Component1</p>
    )
  }
});

var Button1 = React.createClass({
  next: function(){
    ReactDOM.render(<Block2/>, document.getElementById("container"));
  },

  render: function(){
    return(
      <button className = "button1" onClick = {this.next}>Next</button>
    )
  }
});

var Block2 = React.createClass({
  render: function(){
    return(
      <div className="block">
      <Component2/>
      <Button2/>
      </div>
    )
  }
});

var Component2 = React.createClass({
  render: function(){
    return(
      <p className = "component2">This is Component2</p>
    )
  }
});

var Button2 = React.createClass({
  previous: function(){
    ReactDOM.render(<Block1/>, document.getElementById("container"));
  },

  render: function(){
    return(
      <button className = "button1"  onClick = {this.previous}>previous</button>
    )
  }
});

ReactDOM.render(<Block1/>, document.getElementById("container"));

【问题讨论】:

  • 你应该在顶部渲染单个组件,然后创建一个状态机来决定渲染哪个步骤以及何时渲染它。听起来你想做一个巫师。
  • 用这段代码创建一个 JSfiddle,我会帮忙编辑。
  • @BlairAnderson 这是小提琴link

标签: javascript reactjs react-jsx jsx


【解决方案1】:

您绝对不想在组件结构中的其他任何地方使用ReactDOM.render

看起来您正在通过几个不同的步骤创建“向导”。

我编辑了你的小提琴:https://jsfiddle.net/guq81pa9/1/

顶级组件会跟踪您所处的“步骤”,并处理来回切换:

var Block = React.createClass({
  getInitialState: function(){
    return {
      step: 1
    }
  },
  goto: function(step){
    this.setState({
      step: step || 1 // default to step 1
    })
  },
  render: function(){
    var renderStep =  <div className="block component1">
        <Component1/>
        <Button onClick={this.goto.bind(this,2)}>Next</Button>
      </div>

    if (this.state.step === 2) {
      renderStep =  <div className="block component2">
        <Component2/>
        <Button onClick={this.goto.bind(this,1)}>Previous</Button>
      </div>
    }

    return renderStep
  }
});

【讨论】:

    【解决方案2】:

    有没有办法仅在单击按钮时更改&lt;Block1&gt; 中的组件?

    是的。

    解决这个问题的一种方法是让主要的顶级组件&lt;Block1&gt;,或者我们称之为&lt;MainBlock&gt;,成为一个有状态的组件,它维护状态并驱动确定渲染内容的逻辑。其他组件可能只是根据&lt;MainBlock&gt; 设置的状态标志呈现的无状态表示组件。

    基本上,&lt;MainBlock&gt; 有一个状态标志,比如说isShowingNext,它用于确定渲染哪个部分(“下一个”或“上一个”),并通过按钮调用的操作设置该标志。

    就按钮本身而言,它们附加了 onClick 侦听器,无论何时单击,都会在 &lt;MainBlock&gt;&lt;MainBlock&gt; 中调用一个操作来更新状态标志并重新呈现正确的组件。

    由于按钮几乎相同,我们可以将它们组合成一个按钮组件,例如&lt;ToggleButton&gt;,它将根据传递的标志有条件地呈现(“上一个”或“下一个”)(参见 第一种方法)。

    根据您的用例,如果按钮(及其呈现逻辑)不太相似,您可以使用其中两个,例如 &lt;ButtonPrev&gt;&lt;ButtonNext&gt;,其中一个或另一个由&lt;MainBlock&gt; 取决于州旗(参见第二种方法)。

    第一种方法

    jsFiddle sample
    var MainBlock = React.createClass({
    
      // initially we are showing the "previous" page
      getInitialState() {
        return {
          isShowingNext: false
        };
      },
    
      // action that updates the state flag to determine what gets rendered
      handleUpdateIsShowingNext: function(isShowingNext) {
        this.setState({
          isShowingNext: isShowingNext
        });
      },
    
      // render function that displays the proper template based on the state flag
      render: function(){
        var isShowingNext = this.state.isShowingNext;
        return (
          <div className="block">
            {isShowingNext ? <ComponentNext/> : <ComponentPrev/>}
            <ToggleButton  isShowingNext={isShowingNext}
                            onUpdateIsShowingNext={this.handleUpdateIsShowingNext}
            />
          </div>
        );
      }
    });
    
    // button for that toggles between "previous" or "next" page depending on the logic
    var ToggleButton = React.createClass({
      toggle: function(){
        this.props.onUpdateIsShowingNext(!this.props.isShowingNext); // toggle the "isShowingNext" flag
      },
    
      render: function(){
        var isShowingNext = this.props.isShowingNext;
        if (isShowingNext) {
            return <button className="button-prev" onClick={this.toggle}>Prev</button>;
        } else {
            return <button className="button-next" onClick={this.toggle}>Next</button>;
        }
      }
    });
    
    // representational component for the "previous" page
    var ComponentPrev = React.createClass({
      render: function(){
        return <p className = "component-prev">This is ComponentPrev</p>;
      }
    });
    
    // representational component for the "next" page
    var ComponentNext = React.createClass({
      render: function(){
        return <p className = "component-next">This is ComponentNext</p>;
      }
    });
    
    ReactDOM.render(<MainBlock/>, document.getElementById("container"));
    

    第二种方法

    jsFiddle sample
    var MainBlock = React.createClass({
    
      // initially we are showing the "previous" page
      getInitialState() {
        return {
          isShowingNext: false
        };
      },
    
      // returns the template for the "previous" page
      getTemplateForPrev: function() {
        return (
          <div className="block">
            <ComponentPrev/>
            <ButtonPrev onUpdateIsShowingNext={this.handleUpdateIsShowingNext}/>
          </div>
        );
      },
    
      // returns the template for the "next" page
      getTemplateForNext: function() {
        return (
          <div className="block">
            <ComponentNext/>
            <ButtonNext onUpdateIsShowingNext={this.handleUpdateIsShowingNext}/>
          </div>
        );
      },
    
      // action that updates the state flag to determine what gets rendered
      handleUpdateIsShowingNext: function(isShowingNext) {
        this.setState({
          isShowingNext: isShowingNext
        });
      },
    
      // render function that displays the proper template based on the state flag
      render: function(){
        return this.state.isShowingNext ? this.getTemplateForNext() : this.getTemplateForPrev();
      }
    });
    
    // representational component for the "previous" page
    var ComponentPrev = React.createClass({
      render: function(){
        return <p className = "component-prev">This is ComponentPrev</p>;
      }
    });
    
    // button for the "previous" page
    var ButtonPrev = React.createClass({
      next: function(){
        this.props.onUpdateIsShowingNext(true); // clicking "previous" makes isShowingNext be true
      },
    
      render: function(){
        return <button className="button-prev" onClick={this.next}>Next</button>;
      }
    });
    
    // representational component for the "next" page
    var ComponentNext = React.createClass({
      render: function(){
        return <p className = "component-next">This is ComponentNext</p>;
      }
    });
    
    // button for the "next" page
    var ButtonNext = React.createClass({
      previous: function(){
        this.props.onUpdateIsShowingNext(false); // clicking "previous" makes isShowingNext be false
      },
    
      render: function(){
        return <button className="button-next"  onClick={this.previous}>previous</button>;
      }
    });
    
    ReactDOM.render(<MainBlock/>, document.getElementById("container"));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-28
      • 1970-01-01
      • 2021-12-30
      相关资源
      最近更新 更多