有条件地加载Reactjs组件时减少代码冗余

时间:2016-05-25 17:58:45

标签: javascript reactjs react-jsx jsx

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

我想要实现的是,当我按下&#34; next&#34; 按钮<Button1>时,<Component2>必须在<Block1>内加载并且&#34; next&#34; 按钮应更改为&#34;之前的&#34; ,但点击&#34;之前&#34 ; <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"));

2 个答案:

答案 0 :(得分:2)

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

看起来你正在创建一个&#34;向导&#34;有几个不同的步骤。

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

顶级组件会跟踪哪个&#39;步骤&#39;你继续,并处理来回切换:

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

答案 1 :(得分:1)

  

是否有办法仅在按钮点击时更改<Block1>内的组件?

是。

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

基本上,<MainBlock>有一个状态标志,比方说isShowingNext,它用于确定哪个部分(“下一个”或“前一个”)被渲染,并且该标志由被调用的动作设置从按钮。

就按钮本身而言,它们附有onClick侦听器,无论何时单击,都会调用<MainBlock>中的动作并<MainBlock>更新状态标志并重新呈现正确的组件。

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

根据您的使用情况,如果按钮(及其渲染逻辑)不相似,您可以使用其中两个,例如<ButtonPrev><ButtonNext>,其中一个或另一个由<MainBlock>呈现,具体取决于州旗(请参阅第二种方法)。

第一种方法

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