【问题标题】:Change component state on button click单击按钮时更改组件状态
【发布时间】:2016-07-11 01:07:38
【问题描述】:

以下是 HTML。

<script src="https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-xtp1/t39.3284-6/12624079_897774290317920_1379776191_n.js"></script>
<script src="https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-xfp1/t39.3284-6/12624052_751451571621845_431133942_n.js"></script>


<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.24/browser.min.js"></script>

<div class="row" id="container">
  <div class="controls">
    <span class="" id="controls-size">Size : 
        <button id="controls-size-small">SMALL</button>
        <button id="controls-size-med">MEDIUM</button>
        <button id="controls-size-large">LARGE</button>
    </span>

  </div>
  <div id="game-container">
  </div>
</div>

以下是 JavaScript

var SizeEnum = {
  SMALL: 1,
  MEDIUM: 2,
  LARGE: 3
};

var Board = React.createClass({
      getInitialState: function() {
        return {
          size: SizeEnum.MEDIUM
        };
      },

      componentWillMount: function() {
        if (this.state.size == SizeEnum.SMALL) {
          this.style = {
            width: 600 + 'px',
            height: 320 + 'px',
            margin: 'auto',
            border: '2px solid red'
          }
        } else if (this.state.size == SizeEnum.MEDIUM) {
          this.style = {
            width: 700 + 'px',
            height: 500 + 'px',
            margin: 'auto',
            border: '2px solid red'
          }
        } else if (this.state.size == SizeEnum.LARGE) {
          this.style = {
            width: 900 + 'px',
            height: 720 + 'px',
            margin: 'auto',
            border: '2px solid red'
          }
        }
      },

      render: function() {
          return ( < div style = {
            this.style
          } > < /div>
    )
  }

});

ReactDOM.render(<Board / > , document.getElementById("game-container"));

还有一些 CSS

#game-container {
    position: relative;
    margin-top: 32px;
    border: 1px solid black;
    width: 100%;
}

我想要的是,当点击相应的按钮时,Board 组件的大小将调整为适当的大小。

我试过这样做

var board = ReactDOM.render(<Board />, document.getElementById("game-container"));

document.getElementById("controls-size-small").onclick = changeBoardSize;
document.getElementById("controls-size-med").onclick = changeBoardSize;
document.getElementById("controls-size-large").onclick = changeBoardSize;

function changeBoardSize(event) {
    var etid = event.target.id;
    console.log(etid);
    if (etid == "controls-size-small") {
        // method 1
        board.state.size = SizeEnum.SMALL;
    } else if (etid == "controls-size-med") {
        // method 2
        board.state.size = SizeEnum.MEDIUM;
        ReactDOM.render(<Board />, document.getElementById("game-container"));
    } else if (etid == "controls-size-small") {
        // method 3
        board.setState({size: SizeEnum.SMALL});
        ReactDOM.render(<Board />, document.getElementById("game-container"));
    }
}

但它不起作用。

【问题讨论】:

  • 为什么html里面有按钮? React 是基于组件的,所有“html”都应该在渲染函数中的 JSX 中
  • 同意上面的,那些按钮应该是组件,那么这个就很简单了
  • 好的,所以我制作按钮组件.. 然后呢?
  • @dorado 在制作按钮组件后,您应该能够将 onClick 函数附加到它们,在该 onClick 中可以更改状态
  • 这样onClick按钮就能改变板子的状态?

标签: javascript html reactjs


【解决方案1】:

这是一种反模式,尽管这是实现您所寻找的正确方法。

由于 ReactDOM.render 返回一个被渲染组件的实例,你可以使用它并更新它的状态。

    function changeBoardSize(event) {
        var etid = event.target.id;
        console.log(etid);
        if (etid == "controls-size-small") {      
            board.setState({size: SizeEnum.SMALL});
        } else if (etid == "controls-size-med") {
            board.setState({size: SizeEnum.MEDIUM});     
        } else if (etid == "controls-size-small") {
            board.setState({size: SizeEnum.LARGE});
        }
    }

这样做的正确方法是制作 Board 的按钮组件并在其上附加事件处理程序,例如:

var Board = React.createClass({
      getInitialState: function() {
        return {
          size: SizeEnum.MEDIUM
        };
      },
      render: function() {
        return (
        <div>
           <a href="#" onClick={this.onSizeChangeClick.bind(this, SizeEnum.SMALL)}>Small</a>
           <a href="#" onClick={this.onSizeChangeClick.bind(this, SizeEnum.MEDIUM)}>Medium</a>
           <a href="#" onClick={this.onSizeChangeClick.bind(this, SizeEnum.LARGE)}>Large</a>
        </div>  
        )
      },

      onSizeChangeClick: function(size, event){
        event.preventDefault();
        this.setState({
          size: size
        });
      }
})

【讨论】:

  • 如您所见,我已经在上面的方法3中尝试过,但它不起作用。
  • @dorado 你试过什么方法,能给我发个plunker吗?
  • 有趣。我没有意识到 ReactDom.render 的结果将允许您在该组件上设置状态。学到了新东西!无论如何,我仍然坚持我的回答,将所有内容都保留在 React 中会更加 Reactified。
  • 在 render 方法中绑定会导致创建 onSizeChangeClick 的多个副本,这可能会导致大量事件出现问题。最好在构造函数中做bind命令。
  • @DataMania 我完全同意
【解决方案2】:

您采取了错误的方法。 react 最难的部分是“在 React 中思考”。如果你想让事情正常工作,直接进入 DOM 的想法,就像你对 document.getElementById 所做的那样,是不可行的。

最简单的入门方法是在 Board 组件的渲染函数中渲染按钮。然后你可以在 Board 组件中放置一个点击处理程序来设置状态。

这应该让你开始:

    handleClick: function (event) {
       this.setState({ size: SizeEnum.SMALL });
    },
    render: function() {
              return ( 
                  <div>
                      <div style = { this.style}></div>
                      <input type="button" onClick={this.handleClick}
                  </div>
              )
    }

一旦你得到这个工作,如果你想把你的按钮和你的按钮分开,那么你会想要考虑使用 Flux 实现在组件之间传递状态。

【讨论】:

    【解决方案3】:

    你不能像那样设置 React 组件的状态。并且组件应该负责设置自己的状态。

    在您的 Board 组件中,在 componentDidMount 中设置事件侦听器。最好的解决方案是让按钮成为 React 应用程序的一部分,但这超出了这个问题的范围。因此,假设按钮不是 React 应用程序的一部分,然后执行以下操作:

    var Board = React.createClass({
      ...
      ...
      componentDidMount: function(){
        var that = this;
        document.getElementById("controls-size-small").addEventListener('click', that.changeBoardSize, false);
        document.getElementById("controls-size-med").addEventListener('click', that.changeBoardSize, false);
        document.getElementById("controls-size-large").addEventListener('click', that.changeBoardSize, false);
      }
    
      changeBoardSize: function(e){
        /* get the element id and do the enum things here */
        this.setState({
          size: newSize
        });
      }
      render: function(){
        ...
        ...
      }
    });
    

    然后将所有 componentWillMount 样式的东西移到 render 函数中。

    更新

    小提琴:https://jsfiddle.net/dannyjolie/r525ux66/

    【讨论】:

    • 按钮对于这个问题的范围至关重要。以能够与 React 状态交互的方式呈现 UI 元素是理解和使用 React 的基础。
    • 当然,在最常见的情况下,我会同意。但在现实世界中,项目经理和你无法控制的不同代码段一​​起玩,规则会有例外。而且由于 OP 使用应用程序外部的按钮提出了问题,所以这是一种可能的解决方案。
    • @dannyjolie 这似乎是一个有利可图的选择,但似乎不起作用
    • 啊,明白了。我仍在学习,刚刚学会了如何从组件外部获取状态。我想我很幸运我的项目是绿色领域的 React,所以一切都可以在 React 中。
    • @dorado 那么你做错了什么。 jsfiddle.net/dannyjolie/r525ux66
    【解决方案4】:

    你不应该直接改变 React 组件的状态。请改用setState 函数。当你调用setState时,React 会重新渲染组件。

    将新函数 setSize 添加到您的 Board 组件中:

        var Board = React.createClass({
            getInitialState: function() {
              return {
                size: SizeEnum.MEDIUM
             };
         },
         setSize: function(size) {
            this._setStyle(size);
            this.setState({size: size});
         },
         _setStyle: fiunction(size) {
            if (size == SizeEnum.SMALL) {
                 this.style = {
                   width: 600 + 'px',
                   height: 320 + 'px',
                   margin: 'auto',
                   border: '2px solid red'
                }
            } else if (size == SizeEnum.MEDIUM) {
                this.style = {
                  width: 700 + 'px',
                  height: 500 + 'px',
                  margin: 'auto',
                  border: '2px solid red'
               }
            } else if (this.state.size == SizeEnum.LARGE) {
                this.style = {
                  width: 900 + 'px',
                  height: 720 + 'px',
                  margin: 'auto',
                  border: '2px solid red'
               }
           }
         },
         componentWillMount: function() {
            this._setStyle(this.state.size);
         },
         // ................
         render: function() {
          return ( <div style={this.style}></div>)
         }
         });
    
         function changeBoardSize(event) {
             var etid = event.target.id;
             console.log(etid);
            if (etid == "controls-size-small") {
                board.setSize(SizeEnum.SMALL);
            } else if (etid == "controls-size-med") {
                 board.setSize(SizeEnum.MEDIUM);
            } else if (etid == "controls-size-small") {
                 board.setSize(SizeEnum.LARGE);
            }
          }
    

    【讨论】:

      猜你喜欢
      • 2013-08-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多