React是一个Facebook和Instagram用来创建用户界面的JavaScript库,用于构建“可预期的”和“声明式的”Web用户界面。 该框架的推出主要为了开发随着时间数据不断变化的大规模应用程序。 具体文档可以参考官网
React具有以下特点:
- 1.声明式设计 −React采用声明范式,可以轻松描述应用。
- 2.高效 −React通过对DOM的模拟,最大限度地减少与DOM的交互。
- 3.灵活 −React可以与已知的库或框架很好地配合。
- 4.JSX − JSX 是 JavaScript 语法的扩展。React 开发不一定使用 JSX ,但我们建议使用它。
- 5.组件 − 通过 React 构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中。
- 6.单向响应的数据流 − React 实现了单向响应的数据流,从而减少了重复代码,这也是它为什么比传统数据绑定更简单。
目录
1、构建与初始化
2、React元素
3、React组件
4、React组件生命周期
5、受控与非受控组件
1、构建与初始化
- 方式一:如果你只是想简单尝试下 React,可以使用stackblitz。在这里,我必须推荐一下这个在线编辑器,你不需要安装任何东西,目前支持angular、react、ionic,迟点应该也会支持vue。支持github帐号登录,可以fork和share,一个专门为Web构建的更聪明、更快的包管理器。
- 方式二:可以使用官网推荐用create-react-app的方式,是开始构建新的React单页面应用的最佳途径。它可以帮你配置开发环境,以便你可以使用最新的 JavaScript 特性,还能提供很棒的开发体验,并为生产环境优化你的应用。
// 在终端下全局安装官网推荐的create-react-app
npm install -g create-react-app
create-react-app my-app
cd my-app
npm start
- 方式三: 可以使用像webpack或Browserify这样的构建工具,以便于编写模块代码并将其压缩,优化加载时间,这里推荐使用webpack方式。
2、React元素
react 是React库的入口点。如果你通过script标签加载React,这些高阶API可用于 React 全局。如果你使用ES6,你可以使用 import React from 'react' 。如果你使用ES5,你可以使用 var React = require('react')
创建React元素有3种方式,注意:官网认为createFactor方法过时了,推荐你使用JSX或直接使用 React.createElement() 来替代它。JSX可以看做JavaScript的语法拓展(eXtension),看起来有点像XML,让我们可以在JavaScript中编写类似HTML的代码。 使用React,可以进行JSX语法到JavaScript的转换。判断一个元素是HTML元素还是React组件的原则是第一个字母是否大写,如果为大写,则认为是React组件,否则认为是HTML元素。如果我们自定义的组件首字母写成小写,那会得不到我们想要的结果。在JSX中可以通过onClick这样的方式来给一个元素添加事件处理函数,在HTML我们还可以用onclick(onclick和onClick是不同的)来添加事件
第一种是React.createElement(type,[props],[...children])
var listItemElement1 = React.createElement('li', {className: 'item-1', key: 'item-1'}, 'Item-1')
var listItemElement2 = React.createElement('li', {className: 'item-2', key: 'item-2'}, 'Item-2')
var listItemElement3 = React.createElement('li', {className: 'item-3', key: 'item-3'}, 'Item-3')
var reactFragment = [listItemElement1, listItemElement2, listItemElement3];
var listOfItems = React.createElement('ul', {className: 'list-of-items'}, reactFragment);
- 第二种是通过创建工厂函数React.createFactory(type),React.DOM.li(...) 是 React.createELement('li', ...) 的一个包装写法,但被官网认为是过时的,有可能最终会被遗弃。
var createListItemElement = React.createFactory('li');
var listItemElement1 = React.DOM.li({className: 'item-1', key: 'item-1'}, 'Item-1')
var listItemElement2 = React.DOM.li({className: 'item-2', key: 'item-2'}, 'Item-2')
var listItemElement3 = React.DOM.li({className: 'item-3', key: 'item-3'}, 'Item-3')
var reactFragment = [listItemElement1, listItemElement2, listItemElement3];
var listOfItems = React.createElement('ul', {className: 'list-of-items'}, reactFragment);
- 第三种是使用JSX创建React元素,编写React的时候,JSX并不是必须的。每一个JSX元素都只是 React.createElement(component, props, ...children) 的语法糖。因此,任何时候你用JSX语法写的代码也可以用普通的 JavaScript 语法写出来。
var listOfItems = <ul className="list-of-items">
<li className="item-1">Item 1</li>
<li className="item-2">Item 2</li>
<li className="item-3">Item 3</li>
</ul>;
//官网例子jsx写法
class Hello extends React.Component {
render() {
return <div>Hello {this.props.toWhat}</div>;
}
}
//编译转成不使用JSX的代码
class Hello extends React.Component {
render() {
return React.createElement('div', null, `Hello ${this.props.toWhat}`);
}
}
ReactDOM.render(
React.createElement(Hello, {toWhat: 'World'}, null),
document.getElementById('root')
);
- 渲染React元素
//格式:ReactDOM.render(ReactElement, DOMElement, callback);
ReactDOM.render(
listOfItems,
document.getElementById('example')
)
3、React组件
- 可以通过三种方式创建React组件,注意,组件类的第一个字母必须大写,否则会报错,比如HelloMessage不能写成helloMessage。另外,组件类只能包含一个顶层标签,否则也会报错。
- 第一种无状态函数式组件,无状态函数式组件形式上表现为只带有一个render方法的组件类,通过函数形式或者ES6 arrow function的形式创建,并且该组件是无state状态的。只要有可能,尽量使用无状态组件。能用React.Component创建的组件的就尽量不用React.createClass形式创建组件。
function HelloComponent(props) {
return <div> Hello {props.name} </div>;
}
ReactDOM.render(
<HelloComponent name="world" />,
document.getElementById('example')
)
- 第二种React.createClass,它是react刚开始推荐的创建组件的方式,是用ES5的写法实现
var InputControlES5 = React.createClass({
propTypes: {//定义传入props中的属性各种类型要求,可以接受任意值,字符串、对象、函数等等。
initialValue: React.PropTypes.string.isRequired
},
defaultProps: { //用来设置组件属性的默认值
initialValue: 'Hello World'
},
getInitialState: function() {//用于定义初始状态,也就是一个对象,这个对象可以通过 this.state 属性读取。
return {
text: this.props.initialValue || 'placeholder'
};
},
handleChange: function(event) {
this.setState({ //事件的回调函数,当用户交互导致状态变化,this.setState 方法就修改状态值,每次修改以后,自动调用this.render方法,再次渲染组件。
text: event.target.value
});
},
render: function() {
return (
<div>
Type something:
<input onChange={this.handleChange} value={this.state.text} />
</div>
);
}
});
ReactDOM.render(
<InputControlES5 />,
document.getElementById('example')
)
- 第三种是React.Component,它是以ES6的形式来创建react的组件的,是React目前极为推荐的创建有状态组件的方式,最终会取代React.createClass形式;相对于 React.createClass可以更好实现代码复用。将上面React.createClass的形式改为React.Component形式如下:
class InputControlES6 extends React.Component {
constructor(props) {
super(props); //调用super,是为了正确获取到this
this.state = {
text: props.initialValue || 'placeholder'
};
this.handleChange = this.handleChange.bind(this); // ES6 类中函数必须手动绑定
}
handleChange(event) {
this.setState({
text: event.target.value
});
}
render() {
return (
<div>
Type something:
<input onChange={this.handleChange} value={this.state.text} />
</div>
);
}
}
InputControlES6.propTypes = {
initialValue: React.PropTypes.string.isRequired
};
InputControlES6.defaultProps = {
initialValue: 'Hello Wrold'
};
ReactDOM.render(
<InputControlES6 />,
document.getElementById('example')
)
React.createClass与React.Component区别
- React.createClass 创建的组件,其每一个成员函数的this都有React自动绑定,任何时候,直接使用this.method即可,函数中的this会被正确设置
- React.Component创建的组件,其成员函数不会自动绑定this,需要开发者手动绑定,否则将它作为事件处理函数被调用时不能通过this获取当前组件实例对象。
- React.Component 有三种手动绑定方法:
1、在构造函数中完成绑定
2、调用时使用method.bind(this)来完成绑定
3、使用arrow function 来绑定 - 组件属性类型 propTypes 及其默认 props 属性 defaultProps 配置不同。
- 组件初始状态state配置不同。React.createClass创建的组件,其状态state是通过getInitState方法方法来配置组件的相关状态。React.Component创建的组件,其状态state是在construct中像初始化组件属性一样声明。
- Mixins的支持不同。React.createClass在创建组件时可以使用mixins属性,以数组的形式来混合类的集合。React.Component不支持Mixins,React开发者社区提供了一个全新的方式来取代Mixins,那就是Higher-Order Components(高阶组件)
//React.createClass
const Contacts = React.createClass({
handleClick() {
console.log(this); // React组件实例
},
render() {
return (
<div onClick={this.handleClick}></div>
);
}
});
//React.Component
class Contacts extends React.Component {
constructor(props) {
super(props);
}
handleClick() {
console.log(this); // null
}
render() {
return (
<div onClick={this.handleClick}></div>
);
}
}
//React.Component绑定this方法
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this); //构造函数中绑定
}
<div onClick={this.handleClick.bind(this)}></div> //使用bind来绑定
<div onClick={()=>this.handleClick()}></div> //使用arrow function来绑定
4、React组件生命周期
组件的生命周期分成三个状态:
- 挂在(Mounting): 这个阶段发生在组件被创建并被插入到DOM时
- 更新(Updating): 这个阶段发生在组件被重新渲染成虚拟DOM并决定实际DOM是否需要更新时
- 卸载(Unmounting): 这个阶段发生在组件从DOM中被删除时
组件挂载阶段
ES5(React.createClass)
- getInitialState()
- componentWillMount()
- render()
- componentDidMount()
ES6(React.Component)
- constructor()
- componentWillMount()
- render()
- componentDidMount()
组件更新阶段
- componentWillReceiveProps()
- shouldComponentUpdate()
- componentWillUpdate()
- render()
- componentDidUpdate()
组件卸载阶段
- componentWillUnmount()
var Hello = React.createClass({
getInitialState: function () {
return {
opacity: 1.0
};
},
componentDidMount: function () {
this.timer = setInterval(function () {
var opacity = this.state.opacity;
opacity -= .05;
if (opacity < 0.1) {
opacity = 1.0;
}
this.setState({
opacity: opacity
});
}.bind(this), 100);
},
render: function () {
return (
<div style={{opacity: this.state.opacity}}>
Hello {this.props.name}
</div>
);
}
});
ReactDOM.render(
<Hello name="world"/>,
document.body
);
5、受控与非受控组件
React 通过props和state来区分组件的属性和状态。其中,props(属性)用来表示组件外部传入的属性,组件内部不能改变。而state(状态)通常表示组件内部的状态,状态是可以并且应该改变的。React通过 props和state的值来渲染组件,组件渲染完毕之后,通过响应用户操作或者异步网络请求等操作更新组件的状态来重新渲染组件。
- 受控组件将表单数据统一存放在 state 中,交由 React 管理,我们就可以根据用户的输入及时作出响应:1、验证输入正确性(输入格式、类型等),并作出反馈 2、根据输入设置其它组件的状态,譬如输入不规范时,提交按钮处于不可用状态
class ControlledForm extends React.Component {
constructor(props) {
super(props);
this.state = {
username: ''
}
this.handleSubmit = this.handleSubmit.bind(this);
this.updateUsername = this.updateUsername.bind(this);
}
updateUsername(e) {
this.setState({
username: e.target.value,
})
}
handleSubmit() {}
render () {
return (
<form onSubmit={this.handleSubmit}>
<input
type='text'
value={this.state.username}
onChange={this.updateUsername} />
<button type='submit'>Submit</button>
</form>
)
}
}
ReactDOM.render(<ControlledForm />, document.getElementById('react-root'))
- 非受控组件和传统的表单数据管理一样,由DOM存放表单数据,可以使用React提供的refs来获得DOM元素的引用。在需要的时候(譬如表单提交的时候)一次性获取表单的值。
class UnControlledForm extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(e) {
e.preventDefault();
console.log("Value: ", this.input.value)
}
render () {
return (
<form onSubmit={this.handleSubmit}>
<input
type='text'
ref={(input) => this.input = input} />
<button type='submit'>Submit</button>
</form>
)
}
}
ReactDOM.render(<UnControlledForm />, document.getElementById('react-root'));
- 参考文献
1、阮一峰React 入门实例教程
2、React从入门到放弃 -- 笔记、教程、Demo