为了让代码更灵活,能够写更多的组件,咱们把这种模式抽象出来,放到一个 Component
类当中:javascript
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
方法就能够了。前端
还有一个额外的 mount
的方法,其实就是把组件的 DOM 元素插入页面,而且在 setState
的时候更新页面:java
const mount = (component, wrapper) => { wrapper.appendChild(component._renderDOM()) component.onStateChange = (oldEl, newEl) => { wrapper.insertBefore(newEl, oldEl) wrapper.removeChild(oldEl) } }
这样的话咱们从新写点赞组件就会变成:react
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
的构造函数为:git
...
constructor (props = {}) {
this.props = props } ...
继承的时候经过 super(props)
把 props
传给父类,这样就能够经过 this.props
获取到配置参数:github
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=" padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: rgb(228, 86, 73);">${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
属性。这样就能够自由配置组件的颜色了。app
只要有了上面那个 Component
类和 mount
方法加起来不足40行代码就能够作到组件化。若是咱们须要写另一个组件,只须要像上面那样,简单地继承一下Component
类就行了:less
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> ` } }
简单好用,如今能够灵活地组件化页面了。Component
完整的代码能够在这里找到 reactjs-in-40。函数
咱们用了很长的篇幅来说一个简单的点赞的例子,而且在这个过程里面一直在优化编写的方式。最后抽离出来了一个类,能够帮助咱们更好的作组件化。在这个过程里面咱们学到了什么?工具
组件化能够帮助咱们解决前端结构的复用性问题,整个页面能够由这样的不一样的组件组合、嵌套构成。
一个组件有本身的显示形态(上面的 HTML 结构和内容)行为,组件的显示形态和行为能够由数据状态(state)和配置参数(props)共同决定。数据状态和配置参数的改变都会影响到这个组件的显示形态。
当数据变化的时候,组件的显示须要更新。因此若是组件化的模式能提供一种高效的方式自动化地帮助咱们更新页面,那也就能够大大地下降咱们代码的复杂度,带来更好的可维护性。
好了,课程结束了。你已经学会了怎么使用 React.js 了,由于咱们已经写了一个——固然我是在开玩笑,可是上面这个 Component
类其实和 React 的 Component
使用方式很相似。掌握了这几节的课程,你基本就掌握了基础的 React.js 的概念。
接下来咱们开始正式进入主题,开始正式介绍 React.js。你会发现,有了前面的铺垫,下面讲的内容理解起来会简单不少了。
由于第三方评论工具备问题,对本章节有任何疑问的朋友能够移步到 React.js 小书的论坛 发帖,我会回答你们的疑问。