上一節咱們構建了基本的代碼框架,如今開始完善其餘的內容。html
咱們從 ComponentInput
組件開始,學習 React.js 是如何處理用戶輸入的。首先修改 ComponentInput.js
,完善 ComponentInput
的 render
函數中的 HTML 結構:react
import React, { Component } from 'react' class CommentInput extends Component { render () { return ( <div className='comment-input'> <div className='comment-field'> <span className='comment-field-name'>用戶名:</span> <div className='comment-field-input'> <input /> </div> </div> <div className='comment-field'> <span className='comment-field-name'>評論內容:</span> <div className='comment-field-input'> <textarea /> </div> </div> <div className='comment-field-button'> <button> 發佈 </button> </div> </div> ) } } export default CommentInput
在瀏覽器中能夠看到 ComponentInput
的結構和樣式都已經生效:瀏覽器
由於尚未加入處理邏輯,因此你輸入內容,而後點擊發布是不會有什麼效果的。用戶可輸入內容一個是用戶名(username),一個是評論內容(content),咱們在組件的構造函數中初始化一個 state
來保存這兩個狀態:app
... class CommentInput extends Component { constructor () { super() this.state = { username: '', content: '' } } ... } ...
而後給輸入框設置 value
屬性,讓它們的 value
值等於 this.state
裏面相應的值:框架
... <div className='comment-field'> <span className='comment-field-name'>用戶名:</span> <div className='comment-field-input'> <input value={this.state.username} /> </div> </div> <div className='comment-field'> <span className='comment-field-name'>評論內容:</span> <div className='comment-field-input'> <textarea value={this.state.content} /> </div> </div> ...
能夠看到接受用戶名輸入的 <input />
和接受用戶評論內容的 <textarea />
的 value
值分別由 state.username
和 state.content
控制。這時候你到瀏覽器裏面去輸入內容看看,你會發現你什麼都輸入不了。函數
這是爲何呢?React.js 認爲全部的狀態都應該由 React.js 的 state 控制,只要相似於 <input />
、<textarea />
、<select />
這樣的輸入控件被設置了 value
值,那麼它們的值永遠以被設置的值爲準。值不變,value
就不會變化。學習
例如,上面設置了 <input />
的 value
爲 this.state.username
,username
在 constructor
中被初始化爲空字符串。即便用戶在輸入框裏面嘗試輸入內容了,仍是沒有改變 this.state.username
是空字符串的事實。this
因此應該怎麼作才能把用戶內容輸入更新到輸入框當中呢?在 React.js 當中必需要用 setState
才能更新組件的內容,因此咱們須要作的就是:監聽輸入框的 onChange
事件,而後獲取到用戶輸入的內容,再經過 setState
的方式更新 state
中的 username
,這樣 input
的內容纔會更新。spa
... <div className='comment-field-input'> <input value={this.state.username} onChange={this.handleUsernameChange.bind(this)} /> </div> ...
上面的代碼給 input
加上了 onChange
事件監聽,綁定到 this.handleUsernameChange
方法中,該方法實現以下:3d
... handleUsernameChange (event) { this.setState({ username: event.target.value }) } ...
在這個方法中,咱們經過 event.target.value
獲取 <input />
中用戶輸入的內容,而後經過 setState
把它設置到 state.username
當中,這時候組件的內容就會更新,input
的 value
值就會獲得更新並顯示到輸入框內。這時候輸入已經沒有問題了:
相似於 <input />
、<select />
、<textarea>
這些元素的 value
值被 React.js 所控制、渲染的組件,在 React.js 當中被稱爲受控組件(Controlled Component)。對於用戶可輸入的控件,通常均可以讓它們成爲受控組件,這是 React.js 所推崇的作法。另外還有非受控組件,這裏暫時不說起。
一樣地,讓 <textarea />
成爲受控組件:
... handleContentChange (event) { this.setState({ content: event.target.value }) } ... <div className='comment-field'> <span className='comment-field-name'>評論內容:</span> <div className='comment-field-input'> <textarea value={this.state.content} onChange={this.handleContentChange.bind(this)} /> </div> </div> ...
當用戶在 CommentInput
裏面輸入完內容之後,點擊發布,內容實際上是須要顯示到 CommentList
組件當中的。但這兩個組件明顯是單獨的、分離的組件。咱們再回顧一下以前是怎麼劃分組件的:
能夠看到,CommentApp
組件將 CommentInput
和 CommentList
組合起來,它是它們倆的父組件,能夠充當橋接兩個子組件的橋樑。因此當用戶點擊發布按鈕的時候,咱們就將 CommentInput
的 state 當中最新的評論數據傳遞給父組件 CommentApp
,而後讓父組件把這個數據傳遞給 CommentList
進行渲染。
CommentInput
如何向 CommentApp
傳遞的數據?父組件 CommentApp
只須要經過 props
給子組件 CommentInput
傳入一個回調函數。當用戶點擊發布按鈕的時候,CommentInput
調用 props
中的回調函數而且將 state
傳入該函數便可。
先給發佈按鈕添加事件:
... <div className='comment-field-button'> <button onClick={this.handleSubmit.bind(this)}> 發佈 </button> </div> ...
用戶點擊按鈕的時候會調用 this.handleSubmit
方法:
... handleSubmit () { if (this.props.onSubmit) { const { username, content } = this.state this.props.onSubmit({username, content}) } this.setState({ content: '' }) } ...
handleSubmit
方法會判斷 props
中是否傳入了 onSubmit
屬性。有的話就調用該函數,而且把用戶輸入的用戶名和評論數據傳入該函數。而後再經過 setState
清空用戶輸入的評論內容(但爲了用戶體驗,保留輸入的用戶名)。
修改 CommentApp.js
,讓它能夠經過傳入回調來獲取到新增評論數據:
class CommentApp extends Component { handleSubmitComment (comment) { console.log(comment) } render() { return ( <div className='wrapper'> <CommentInput onSubmit={this.handleSubmitComment.bind(this)} /> <CommentList /> </div> ) } }
在 CommentApp
中給 CommentInput
傳入一個 onSubmit
屬性,這個屬性值是 CommentApp
本身的一個方法 handleSubmitComment
。這樣 CommentInput
就能夠調用 this.props.onSubmit(…)
把數據傳給 CommenApp
。
如今在 CommentInput
中輸入完評論內容之後點擊發布,就能夠看到 CommentApp
在控制檯打印的數據:
這樣就順利地把數據傳遞給了父組件,接下來咱們開始處理評論列表相關的邏輯。