2016-03-23 203 views
6

以下是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> 

以下是Javscript

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

我想要的是點擊相應的按鈕時,主板組件被調整到合適的大小。

我試着做這樣

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

但它不工作。

+1

爲什麼你有HTML,其按鈕? React是基於組件的,並且所有的「html」都應該在JSX中的渲染函數 – erichardson30

+0

與上面的意見一致,那些按鈕應該是組件,那麼這很簡單 – JordanHendrix

+0

好吧,我做按鈕組件..然後呢? – dorado

回答

3

您不能像這樣設置React組件的狀態。組件應該負責設置自己的狀態。

在您的Board組件中,在componentDidMount中設置事件偵聽器。最好的解決方案是讓按鈕成爲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/

+0

這些按鈕對於這個問題的範圍至關重要。以可以與React狀態交互的方式呈現UI元素是瞭解和使用React的基礎。 –

+1

絕對,在大多數情況下,我會同意。但在現實世界中,如果項目經理和不可控制的代碼片段在一起播放,則規則將會有例外。而且,由於OP在應用程序外部提供了按鈕問題,所以這裏有一個可能的解決方案。 – dannyjolie

+0

@dannyjolie這似乎是一個有利可圖的選擇,但似乎並沒有工作 – dorado

0

這是一個反模式,雖然這是實現你正在尋找的正確方法。

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

做到這一點,正確的方法,是使董事會的按鈕組件,並在他們身上如附加的事件處理程序:

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

正如你所看到的,我已經在上面的方法3中試過了,但它不起作用。 – dorado

+0

@dorado你有什麼方法可以嘗試,你可以給我一個沉重的? – Burimi

+0

有趣。我沒有意識到ReactDom.render的結果將允許你在該組件上設置狀態。學到了新東西!無論如何,我仍然堅持我的回答,它更接近React中的所有內容。 –

2

你採取錯誤的做法。關於反應最難的部分是「思考反應」。如果您希望事情能夠正常工作,那麼直接訪問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> 
      ) 
    } 

一旦你得到這個工作,如果你想從你的按鈕分開的按鈕,然後你會想看看使用助焊劑實現從組件傳遞狀態組件。

1

你不應該改變直接反應組件的狀態。改用setState函數。當您致電setState React將重新渲染組件。

添加新功能的setSize到您的主板成分,它:

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