说起react是一个很宽泛的东西,作为一个从零开始学习react的小白,到现在懂一点react,决心将自己学的东西一一整理,从简单的开始着手,一是为了巩固知识,二也是为正在学习的同学提供一些思路,三也是希望大佬能够指出我的不妥之处,或加以补充,以更深层次的掌握react。
那么,在学习react之前,我们应该掌握哪些知识?
1.需要熟悉javascript
2.需要使用es6,箭头函数, 类, 模板字符串, let, 和 const 声明
react是什么?概括为两点:
1.用来构建UI的JS库。
2.React 不是一个MVC框架,仅仅是视图层(V)层的库。
react包括哪些概念?
1.组件
2.JSX
3.Virtual DOM
4.Data Flow
第一部分
那么接下来我们就从构建一个简单的组件开始。
在之前,我们的js,css,html都是分离的,这种方式满足不了我们要去实现代码复用。组件化,很多前框的框架都开始注重了这一点。一个组件就是一个功能模块,react框架相对来说,实现的更加彻底一些。react各个组件维护自己的状态和UI,当状态更变时,自动重新渲染整个组件。
构建react组件,可以是一个类,可以是一个函数。类与函数有什么区别?
1.类是有状态的组件,而函数是无状态的组件。
2.通过类构建一个组件,允许有内部状态存在,有完整的生命周期。可以使一个组件有生命力并且便于管理。
3.通过类构建必须要继承react内置的组件类,生命周期都是继承自react内置的组件类。
4.从性能来说,类构建要稍微慢一些。
如果是不使用生命周期是不是就可以不继承内置的组件类呢?
答案是不能,如果是使用了class来构建react的组件,必须要继承react的内置组件,因为class类中必须有一个render()方法来返回组件的实例。不写render方法它就不可能返回UI,那也就不是一个组件。render方法就是生命周期之一。
首先,我们来创建一个基于class的react组件。
类构建react组件有两种方式:
1.ES5: React.createClass
2.ES6:React.Component
React.createClass是React刚开始推荐的方式,是与ES5中原生JS来创建react组件方式。React.createClass创建一个类,接受一个对象为参数,并且需要有一个render方法来返回组件实例UI。这种方式我没有怎么使用过,不过基本的使用方式如下:
import React from 'react'
import ReactDom from 'react-dom'
const reactDom = React.createClass({
getDefaultProp: function () {
return { open: false }
},
getInitialState: function (){
return { open: this.props.open}
},
handleClick: function(event){
this.setState({
open: !this.state.open
})
},
render: function () {
var open = this.state.open
className = open ? 'switch-button' : 'btn-switch'
return (
<label className={className} onClick={this.handleClick.bind(this)}>
<Input type="checkbox" checked={open} />
</label>
)
}
})
ReactDOM.render(
<reactDom />,
document.getElementById('root')
)
ReactDom是React的最基本方法用于将模板转为HTML语言,并插入指定的DOM节点。
虽然没有使用过,但是它的弊端就是:
1.会自动绑定函数方法,造成不必要的性能开销
2.mixins不够直观,自然。(这一点在es6中已经没有使用了,它主要的作用就是,不同的组件之间,会使用到相同的功能,如果一个组件使用了多个 mixins,其中几个 mixins 定义了相同的“生命周期方法”,这些方法会在组件相应的方法执行完之后按 mixins 指定的数组顺序执行),可参考http://wiki.jikexueyuan.com/project/react-tutorial/mixin.html
接下来要说的就是目前正使用的方法,使用es6方式来构建react组件。按照上面的方法,应该写成以下方式。
export default class reactDom extends Component {
constructor(props){
super(props);
this.state = {
open: false
}
}
getDefaultProp() {
return { open: false }
}
getInitialState(){
return { open: this.props.open}
}
handleClick (e){
this.setState({
open: !this.state.open
})
}
render(){
return (
<label className={className} onClick={this.handleClick.bind(this)}>
<Input type="checkbox" checked={open} />
</label>
)
}
}
那么es5与es6在写法上有什么更具体的区别呢?
1.写法上的不同
React.creatClass 新创建的Class赋给一个常量,再添上render方法来构建出一个基本的组件
es5的写法:
const Contacts = React.createClass({
render() {
return (
<div></div>
)
}
})
export default Contacts;
es6的写法:
export default class Contacts extends React.Component({
construct(props){
super(this)
this.state = {}
}
render(){
return(
<div></div>
)
}
})
es6的不同,我们使用super这个函数,来为React.component传递属性,所以需要引用construct()这个方法。es6的写法更加具有类的意义。
2.propType 和 getDefaultProps
他们的区别在于如何使用、声明默认属性和类型,以及如何设置类初始化状态。propType的作用是,当父组件给子组件传参时,定义父组件给子组件传值的类型;getDefaultProps/DefaultProps的任务是父组件给子组件传参没有给定默认值时,可以在getDefaultProps/DefaultProps中定义。
es5写法:
const Contacts = React.createClass({
propType: {},
getDefaultProps: (){
return {
}
}
render() {
return (
<div></div>
)
}
})
export default Contacts
在调用 React.createClass,定义propTypes 的对象,只要给它的属性进行赋值就能声明对应属性的类型。 getDefaultProps 这个函数返回了一个对象,这个对象的所有属性将会作为组件的初始化属性
使用es6的写法,个人更喜欢这样的写法,他更简洁直观了:
export default Contacts extends React.Component {
// static 不继承实例,直接通过类来调用的静态方法
static propType = {
},
static defaultProps = {
}
render() {
return (
<div></div>
)
}
}
3.state的不同
外部数据来源我们用props来储存数据,而state是用来管理内部数据状态的。使用es5,state是放在getInitialState()方法中,返回一个包含组件初始化状态的对象。
es5写法具体如下:
const Contact = React.CreateClass{
getInitialState () {
return {
}
}
render(){
return (
<div></div>
)
}
}
export default Contact;
在es6中,废除了getInitialState()这个方法,状态的定义在construct构造函数里。例如这样:
export default Contact extends React.Component {
construct (props) {
super(props);
this.state = {}
}
render(){
return (
<div></div>
)
}
}
4.this的使用不同
es5中会自动绑定this,比如说
const Contact = React.createClass({
handleClick () {
console.log(this)
},
render(){
return (
<div onClick={this.handleClick}></div>
)
}
})
export default Contact;
这里的this可以自动的找到当前执行环境的上下文,不用我们操心,但是这样我们语法结构时,可能要去改变jsx部分(支持js,css,html混合在一起的写法)结构。
如果使用的是es6的语法,this不会自动去绑定上下文,而是需要自己绑定正确的上下文,就像下面的例子一样。
export default class Contact extends React.Component {
handleClick () {
console.log(this)
}
render () {
return (
<div onClick={this.handleClick.bind(this)}></div>
)
}
}
5.mixins
es5中还保存有mixins这个特性,而es6中已废弃了这个特性,取而代之的是高阶组件,不过这一块还不了解,会继续学习。
接下来,我们创建一个无状态组件
无状态的组件我们通常是做纯UI展示。不需要去定义组件状态不用考虑组件的生命周期,就像这样:
class MessageView extends React.Component {
render({
return(
<div className="container">
<div className="from">
<span className="label">From: </span>
<span className="value">JohnDoe</span>
</div>
<div className="message">
<span className="label">Message: </span>
<span className="value">Have a great day!</span>
</div>
</div>
) } }
export default MessageView;
因为是纯UI展示,所以也可以不考虑生命周期,不继承Component,于是可改写成:
export default function MessageView({message}) {
return(
<div className="container">
<div className="from">
<span className="label">From: </span>
<span className="value">{message.from}</span>
</div>
<div className="message">
<span className="label">Message: </span>
<span className="value">{message.content}</span>
</div>
</div>
) }}
那么无状态与有状态组件,我们怎么用呢?
如果要考虑生命周期,那么就用使用类构建react实例,如果不考虑生命周期,那么使用无状态函数式构建。
一般来说,ES6的写法是优于ES5写法的。
以上是我的总结,如有疑问可留言。
参考资料:
https://www.w3cplus.com/react/stateful-vs-stateless-components.html © w3cplus.com