目前爲止,第二階段知識已經基本介紹完,咱們已經具有了項目上手實戰必備的 React.js 知識,如今能夠把這些知識應用起來。接下來是實戰環節,咱們會繼續上一階段的例子,把評論功能作得更加複雜一點。css
咱們在上一階段的評論功能基礎上加上如下功能需求:html
<code>
元素包含。例如輸入 `console.log` 就會處理成 <code>console.log</code>
再顯示到頁面上。在線演示地址。react
你們能夠在原來的第一階段代碼的基礎上進行修改,第1、二階段評論功能代碼能夠在這裏找到: react-naive-book-examples。能夠直接使用最新的樣式文件 index.css 覆蓋原來的 index.css。git
接下來能夠分析如何利用第二階段的知識來構建這些功能,在這個過程裏面可能會穿插一些小技巧,但願對你們有用。咱們回顧一下這個頁面的組成:github
咱們以前把頁面分紅了四種不一樣的組件:分別是 CommentApp
、CommentInput
、CommentList
、Comment
。咱們開始修改這個組件,把上面的需求逐個完成。瀏覽器
這個功能是很簡單的,咱們須要獲取 textarea
的 DOM 元素而後調用 focus()
API 就能夠了。咱們給輸入框元素加上 ref
以便獲取到 DOM 元素,修改 src/CommentInput.js
文件:app
... <textarea ref={(textarea) => this.textarea = textarea} value={this.state.content} onChange={this.handleContentChange.bind(this)} /> ...
組件掛載完之後完成之後就能夠調用 this.textarea.focus()
,給 CommentInput
組件加上 ComponentDidMount
生命週期:函數
class CommentInput extends Component { static propTypes = { onSubmit: PropTypes.func } constructor () { super() this.state = { username: '', content: '' } } componentDidMount () { this.textarea.focus() } ...
這個功能就完成了。如今體驗還不是很好,接下來咱們把用戶名持久化一下,體驗就會好不少。ui
你們能夠注意到咱們給原來的 props.onSubmit
參數加了組件參數驗證,在此次實戰案例中,咱們都會給評論功能的組件加上 propTypes
進行參數驗證,接下來就不累述。this
用戶輸入用戶名,而後咱們把用戶名保存到瀏覽器的 LocalStorage 當中,當頁面加載的時候再從 LocalStorage 把以前保存的用戶名顯示到用戶名輸入框當中。這樣用戶就不用每次都輸入用戶名了,而且評論框是自動聚焦的,用戶的輸入體驗就好不少。
咱們監聽用戶名輸入框失去焦點的事件 onBlur
:
... <input value={this.state.username} onBlur={this.handleUsernameBlur.bind(this)} onChange={this.handleUsernameChange.bind(this)} /> ...
在 handleUsernameBlur
中咱們把用戶的輸入內容保存到 LocalStorage 當中:
class CommentInput extends Component { constructor () { super() this.state = { username: '', content: '' } } componentDidMount () { this.textarea.focus() } _saveUsername (username) { localStorage.setItem('username', username) } handleUsernameBlur (event) { this._saveUsername(event.target.value) } ...
在 handleUsernameBlur
中咱們把用戶輸入的內容傳給了 _saveUsername
私有方法(全部私有方法都以 _
開頭)。_saveUsername
會設置 LocalStorage 中的 username
字段,用戶名就持久化了。這樣就至關於每當用戶輸入完用戶名之後(輸入框失去焦點的時候),都會把用戶名自動保存一次。
輸入用戶名,而後到瀏覽器裏裏面看看是否保存了:
而後咱們組件掛載的時候把用戶名加載出來。這是一種數據加載操做,咱們說過,不依賴 DOM 操做的組件啓動的操做均可以放在 componentWillMount
中進行,因此給 CommentInput
添加 componentWillMount
的組件生命週期:
... componentWillMount () { this._loadUsername() } _loadUsername () { const username = localStorage.getItem('username') if (username) { this.setState({ username }) } } _saveUsername (username) { localStorage.setItem('username', username) } ...
componentWillMount
會調用 _loadUsername
私有方法,_loadUsername
會從 LocalStorage 加載用戶名而且 setState
到組件的 state.username
中。那麼組件在渲染的時候(render
方法)掛載的時候就能夠用上用戶名了。
這樣體驗就好多了,刷新頁面,不須要輸入用戶名,而且自動聚焦到了輸入框。咱們 一、 2 需求都已經完成。
這裏插入一些小貼示,你們能夠注意到咱們組件的命名和方法的擺放順序其實有必定的講究,這裏能夠簡單分享一下我的的習慣,僅供參考。
組件的私有方法都用 _
開頭,全部事件監聽的方法都用 handle
開頭。把事件監聽方法傳給組件的時候,屬性名用 on
開頭。例如:
<CommentInput onSubmit={this.handleSubmitComment.bind(this)} />
這樣統一規範處理事件命名會給咱們帶來語義化組件的好處,監聽(on
)CommentInput
的 Submit
事件,而且交給 this
去處理(handle
)。這種規範在多人協做的時候也會很是方便。
另外,組件的內容編寫順序以下:
defaultProps
、propTypes
。constructor
。_
開頭的私有方法。handle*
。render*
開頭的方法,有時候 render()
方法裏面的內容會分開到不一樣函數裏面進行,這些函數都以 render*
開頭。render()
方法。若是全部的組件都按這種順序來編寫,那麼維護起來就會方便不少,多人協做的時候別人理解代碼也會一目瞭然。