本文做者:鬍子大哈
本文原文:huziketang.com/books/react…javascript
轉載請註明出處,保留原文連接以及做者信息前端
在線閱讀:huziketang.com/books/reactjava
爲了讓代碼更靈活,能夠寫更多的組件,咱們把這種模式抽象出來,放到一個 Component
類當中:react
class Component {
setState (state) {
const oldEl = this.el
this.state = state
this.el = this._renderDOM()
if (this.onStateChange) this.onStateChange(oldEl, this.el)
}
_renderDOM () {
this.el = createDOMFromString(this.render())
if (this.onClick) {
this.el.addEventListener('click', this.onClick.bind(this), false)
}
return this.el
}
}複製代碼
這個是一個組件父類 Component
,全部的組件均可以繼承這個父類來構建。它定義的兩個方法,一個是咱們已經很熟悉的 setState
;一個是私有方法 _renderDOM
。_renderDOM
方法會調用 this.render
來構建 DOM 元素而且監聽 onClick
事件。因此,組件子類繼承的時候只須要實現一個返回 HTML 字符串的 render
方法就能夠了。git
還有一個額外的 mount
的方法,其實就是把組件的 DOM 元素插入頁面,而且在 setState
的時候更新頁面:github
const mount = (component, wrapper) => {
wrapper.appendChild(component.renderDOM())
component.onStateChange = (oldEl, newEl) => {
wrapper.insertBefore(newEl, oldEl)
wrapper.removeChild(oldEl)
}
}複製代碼
這樣的話咱們從新寫點贊組件就會變成:app
class LikeButton extends Component {
constructor () {
this.state = { isLiked: false }
}
onClick () {
this.setState({
isLiked: !this.state.isLiked
})
}
render () {
return ` <button class='like-btn'> <span class='like-text'>${this.state.isLiked ? '取消' : '點贊'}</span> <span>👍</span> </button> `
}
}
mount(new LikeButton(), wrapper)複製代碼
這樣還不夠好。在實際開發當中,你可能須要給組件傳入一些自定義的配置數據。例如說想配置一下點贊按鈕的背景顏色,若是我給它傳入一個參數,告訴它怎麼設置本身的顏色。那麼這個按鈕的定製性就更強了。因此咱們能夠給組件類和它的子類都傳入一個參數 props
,做爲組件的配置參數。修改 Component
的構造函數爲:less
...
constructor (props = {}) {
this.props = props
}
...複製代碼
繼承的時候經過 super(props)
把 props
傳給父類,這樣就能夠經過 this.props
獲取到配置參數:dom
class LikeButton extends Component {
constructor (props) {
super(props)
this.state = { isLiked: false }
}
onClick () {
this.setState({
isLiked: !this.state.isLiked
})
}
render () {
return ` <button class='like-btn' style="background-color: ${this.props.bgColor}"> <span class='like-text'> ${this.state.isLiked ? '取消' : '點贊'} </span> <span>👍</span> </button> `
}
}
mount(new LikeButton({ bgColor: 'red' }), wrapper)複製代碼
這裏咱們稍微修改了一下原有的 LikeButton
的 render
方法,讓它能夠根據傳入的參數 this.props.bgColor
來生成不一樣的 style
屬性。這樣就能夠自由配置組件的顏色了。函數
只要有了上面那個 Component
類和 mount
方法加起來不足40行代碼就能夠作到組件化。若是咱們須要寫另一個組件,只須要像上面那樣,簡單地繼承一下 Component
類就行了:
class RedBlueButton extends Component {
constructor (props) {
super(props)
this.state = {
color: 'red'
}
}
onClick () {
this.setState({
color: 'blue'
})
}
render () {
return ` <div style='color: ${this.state.color};'>${this.state.color}</div> `
}
}複製代碼
簡單好用,如今能夠靈活地組件化頁面了。
噢,忘了,還有一個神祕的 createDOMFromString
,其實它更簡單:
const createDOMFromString = (domString) => {
const div = document.createElement('div')
div.innerHTML = domString
return div
}複製代碼
Component
完整的代碼能夠在這裏找到 reactjs-in-40。
咱們用了很長的篇幅來說一個簡單的點讚的例子,而且在這個過程裏面一直在優化編寫的方式。最後抽離出來了一個類,能夠幫助咱們更好的作組件化。在這個過程裏面咱們學到了什麼?
組件化能夠幫助咱們解決前端結構的複用性問題,整個頁面能夠由這樣的不一樣的組件組合、嵌套構成。
一個組件有本身的顯示形態(上面的 HTML 結構和內容)行爲,組件的顯示形態和行爲能夠由數據狀態(state)和配置參數(props)共同決定。數據狀態和配置參數的改變都會影響到這個組件的顯示形態。
當數據變化的時候,組件的顯示須要更新。因此若是組件化的模式能提供一種高效的方式自動化地幫助咱們更新頁面,那也就能夠大大地下降咱們代碼的複雜度,帶來更好的可維護性。
好了,課程結束了。你已經學會了怎麼使用 React.js 了,由於咱們已經寫了一個——固然我是在開玩笑,可是上面這個 Component
類其實和 React 的 Component
使用方式很相似。掌握了這幾節的課程,你基本就掌握了基礎的 React.js 的概念。
接下來咱們開始正式進入主題,開始正式介紹 React.js。你會發現,有了前面的鋪墊,下面講的內容理解起來會簡單不少了。