2016-10-10 17 views
0

我想學習React。我已經對JavaScript有了很好的把握。我試圖通過創建一個基本上是任務管理器的小應用程序來學習。在我的情況下,這是與雜貨有關的項目。我在這裏創建了一個小提琴。你能否看看我如何編寫反應代碼,並讓我知道這是用組件/類構建的最佳方法?你可以看到我有嵌套的組件。我不確定是否有更好的方法來做到這一點。學習React.js

最後,我不想在用戶每次點擊大藍色的添加按鈕時創建一個新的「添加項目行」。現在顯示的是默認值,但我不想默認顯示。我只想在用戶點擊添加按鈕時創建一個(add-item-row,div)。

這是小提琴。

https://jsfiddle.net/j0mpsbh9/4/

<div id="app" class="container"> 
     <script type="text/babel"> 
     var AddItemWrapper = React.createClass({ 
    render: function() { 
     return (
      <div> 
       <div className="row"> 
        <AppTitle /> 
        <AddItemForm /> 
       </div> 
        <AddItemRow /> 
      </div> 
     ); 
    } 
}); 

var AppTitle = React.createClass({ 
    render: function() { 
     return (
      <div> 
       <h1>Grocery List</h1> 
      </div> 
     ); 
    } 
}); 

var AddItemForm =React.createClass({ 
    render: function() { 
     return (
      <div> 
       <div className="col-sm-6 col-lg-6"> 
        <div className="form-group"> 
        <label htmlFor="enter-grocery-item" className="sr-only">Enter Grocery Item</label> 
        <input type="text" className="form-control" id="enter-grocery-item" placeholder="Enter Grocery Item" /> 
        </div> 
       </div> 
       <div className="col-sm-6 col-lg-6"> 
        <button type="button" id="add" className="btn btn-block btn-info">Add <span className="glyphicons circle_plus"></span></button> 
       </div> 
      </div> 
     ); 
    } 
}); 

var AddItemRow =React.createClass({ 
    render: function() { 
     return (
      <div className="add-item-row"> 
       <div className="row"> 
        <div className="col-sm-12 grocery-items"> 
         <div className="col-sm-6"> 
          <div className="form-group"> 
          <label htmlFor="grocery-item" className="sr-only">Grocery Item</label> 
          <input type="text" className="form-control" id="grocery-item" placeholder="" /> 
          </div> 
         </div> 
         <div className="col-sm-6 center"> 
          <button type="button" className="btn btn-blockx btn-warning"><span className="glyphicons pencil"></span></button> 
          <button type="button" className="btn btn-blockx btn-lgx btn-danger"><span className="glyphicons remove"></span></button> 
          <button type="button" className="btn btn-blockx btn-lgx btn-success"><span className="glyphicons thumbs_up"></span></button> 
         </div> 
        </div> 
       </div> 
      </div> 
     ); 
    } 
}); 

ReactDOM.render(
    <AddItemWrapper />, 
    document.getElementById('app') 
); 
    </script> 
</div> 
+0

您應該使用模塊捆綁器(例如webpack)將組件/容器劃分爲不同的文件。 – jbpark

回答

1

您有一個好的開始在這裏!您的組件層次結構以合理的方式進行組織。但是你錯過了任何一種交互或內部狀態。

您使React組件互動的主要方式是使用state加上事件回調函數,它修改了上述state。 「狀態」非常明顯 - 它描述了組件的外觀和行爲固有的價值,但隨着時間的推移而變化。每次React組件的state被更改(使用this.setState())時,該組件將重新呈現(字面上通過重新運行render()函數)以反映更改。

首先讓我們編輯您的AddItemWrapper類,以便跟蹤第一次安裝時的某些內部狀態。我們知道,你想擁有多行數據,讓我們給它一個空數組存儲有關行未來的信息:

getInitialState(){ 
    return {rows: []}; 
}, 

現在,而不是直接渲染單個AddItemRow,我們將呈現一組動態的基於當前組件狀態的行。 Array.map()是完美的,這和普通的使用情況陣營:

{this.state.rows.map(function(ea, i){ 
    return <AddItemRow initialItemName={ea} key={ea + "-" + i} /> 
})} 

基本上是什麼做的是採取陣列AddItemWrapper.state.rows陣列中的每個條目,使得它作爲AddItemRow組件。我們給它兩個屬性,initialItemName和key。 「initialItemName」只會告訴子組件它的名字是什麼時候被添加的,而「key」是一個唯一的字符串,它允許React區分組件和它們的兄弟姐妹。

現在我們已經設置了AddItemWrapper來根據其內部狀態正確渲染行。接下來,我們必須修改AddItemForm,以便它對用戶輸入做出反應並觸發添加的新行。

在AddItemForm中,首先我們需要在輸入文本框中添加一個「ref」。這是爲了讓陣營可以從這個HTML元素識別和讀取數據它之後被渲染:

<input ref={function(el){this.inputElement = el;}.bind(this)} ... /> 

然後給按鈕元素的回調單擊時,將觸發:

<button onClick={this.handleClick} ... /> 

最後寫回調處理器本身:

handleClick(){ 
    this.props.onAdd(this.inputElement.value); 
    this.inputElement.value = ""; 
} 

請注意這個回調是如何調用this.props.onAdd()?這意味着我們需要將一個回調函數從父類(AddItemWrapper)傳遞給此組件以供使用。這就是我們在React中的父母與孩子之間的溝通方式:將一個父母的功能傳遞給孩子,這個孩子將從孩子內部觸發,但會影響父母。

在AddItemWrapper我們確保AddItemForm訪問回調函數:

AddItemForm onAdd={this.onAdd} /> 

然後我們寫的回調函數本身:

onAdd(newItem){ 
    var newRows = this.state.rows.slice(); 
    newRows.push(newItem); 
    this.setState({rows: newRows}); 
} 

通知我們如何複製保存舊數組在state(使用Array.slice()),將新項目推入新陣列,然後用新陣列更新狀態?不要直接改變state;總是複製它,修改副本,然後用新副本更新state

幾乎完成。我們創建了AddItemWrapper渲染其行的方式,以及AddItemForm創建新行的方式。現在我們編輯AddItemRow以保持其內部狀態的方式進行渲染。

首先確保它在掛載時初始化自己的狀態。我們會記錄一個字符串值,最初與用戶按下「添加」時輸入的文本框中的值相同,但由於它保留在AddItemRow.state中,所以用戶可以稍後修改它:

getInitialState() { 
    return {itemName: this.props.initialItemName} 
} 

現在該行的名稱保持在組件的狀態,我們可以使它在HTML這樣的:

<input value={this.state.itemName} ... /> 

Here's what it looks like when you put it all together!

顯然還有更多的功能,你想添加,例如讓用戶編輯,移動或d請輸入一行。我會把這些練習留給你。我強烈建議你仔細閱讀所有的the official documentation以及做一些教程,讓你的頭腦在遊戲中。很明顯,根據你目前的狀況,你有一些經驗,但如何獲得staterender()和回調的工作方式需要一些練習。祝你好運!

+0

非常感謝您的幫助! – user3259232