一、JSX 语法
支持Html+JavaScript混写。
允许直接在模板中插入JavaScript变量。如果这个变量是一个数组,则会展开这个数组的所有成员。
在模板中插入数组变量时,要明确key,react的key关乎到react的dom-diff算法。react中对于dom的操作是根据生成的data-reactid进行绑定的,添加key可以保证dom结构的完整性,而不会根据react自己对dom标记的key进行重新分配。
1
2
3
4
5
6
7
8
9
10
11
12
13let names = ['Alice', 'Emily', 'Kate'];
let keyid = 0;
ReactDOM.render(
<div
{
names.map((name) = {
return <div key = {keyid++}Hello, { name } !</div
})
}
</div,
document.getElementById('example')
);
二、组件
React 版本 16 以前:
1
2
3
4
5
6# React.createClass() 用于生成一个组件类
let HelloMessage = React.createClass({
render: () = {
return <h1Hello { this.props.name }</h1
}
});React 版本 16 以后:
1
2
3
4
5
6
7
8
9
10
11class HelloMessage extends React.Component{
render(){
return (
<h1Hello { this.props.name } !</h1
)
}
}
ReactDOM.render(
<HelloMessage name="Eva"/,
document.getElementById("example")
)所有组件都要有自己的render方法,用于输出组件。
组件类的第一个字母必须大写,否则会报错。
组件类只能包含一个顶层标签。
组件的属性可以在组件类的this.props对象上获取,比如:this.props.name。
添加组件属性,class属性需要写成className,for属性需要写成htmlFor。这是因为class和for是 JavaScript 的保留字。
三、this.props.children
this.props对象的属性与组件的属性一一对应,但是this.props.children除外
this.props.children表示组件的所有子节点
this.props.children的值有三种可能:
- undefind —— 没有子节点
- object —— 只有一个子节点
- array —— 有多个子节点
我们可以用 React.Children.map 来遍历子节点
四、PropTypes 组件实例属性验证
参考
npm安装
1
npm install prop-types --save
CDN引用:
1
<script src="https://cdn.bootcss.com/prop-types/15.6.1/prop-types.js"</script>
常用数据类型检测
- 字符串类型PropTypes.string
- 布尔类型PropTypes.bool
- 函数类型PropTypes.func
- 数组类型PropTypes.array
- 数字类型PropTypes.number
- 对象类型PropTypes.object
- 元素PropTypes.element
- 传入任何东西都可以PropTypes.node
- 选择特定值PropTypes.oneOf([‘是’, ‘否’, “是否”])
- 选择诸多类型中的一种(任意类型)PropTypes.oneOfType
实例:PropTypes静态类型校验
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16class MyTitle extends React.Component {
render() {
return <div{this.props.title}</div;
}
}
MyTitle.propTypes = {
title: PropTypes.string.isRequired,
};
let data = 123;
ReactDOM.render(
<MyTitle title={data}/,
document.getElementById("example")
)
// => Warning: Failed prop type: Invalid prop `title` of type `number` supplied to `MyTitle`, expected `string`.实例:设置组件属性默认值
1
2
3
4
5
6
7
8
9
10
11
12
13class MyTitle extends React.Component {
render() {
return <h1{this.props.title}</h1;
}
}
MyTitle.defaultProps = {
title: 'defaultTitle',
};
ReactDOM.render(
<MyTitle/,
document.getElementById("example")
)
五、ref 属性获取真实的DOM节点
- 由于this.refs.[refName]属性获取的是真实的DOM节点,所以必须等到虚拟DOM插入文档后才能使用这个属性
下面实例中,要保证真实DOM发生在事件之后,才能读取到this.refs.[refName]属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18class MyComponent extends React.Component{
handleClick = () = {
this.refs.myTextInput.focus();
};
render = () = {
return (
<div
<input type="text" ref="myTextInput"/
<input type="button" value="Focus the text input" onClick={this.handleClick}/
</div
)
};
}
ReactDOM.render(
<MyComponent/,
document.getElementById('example')
)
六、this.state
阮一峰教程中使用了getInitialState方法,该方法只能与CreateClass一起使用
使用React.Component时,需要搭配constructor
this.setState方法不能直接写在constructor中
只要组件存在constructor,就必须写super,否则this.props将是未定义
两者的具体区别请对照阮一峰教程和React官方文档
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24class LikeButton extends React.Component{
constructor(props) {
super(props);
this.state = { liked: false };
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
this.setState({
liked: !this.state.liked
})
};
render(){
let text = this.state.liked ? 'like' : 'have not liked';
return (
<p onClick={this.handleClick}
You {text} this. Click to toggle.
</p
)
}
}
ReactDOM.render(
<LikeButton/,
document.getElementById('example')
)
七、表单
表单需要用户和组件互动,所以不能用this.props直接读取
textarea 元素、select元素、radio元素都属于这种情况
要定义一个 onChange 事件的回调函数,通过 event.target.value 读取用户输入的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23class Input extends React.Component{
constructor(props){
super(props);
this.state = {value: "Hello!"};
this.handleChange = this.handleChange.bind(this);
}
handleChange(event){
this.setState({ value: event.target.value })
}
render(){
let value = this.state.value;
return (
<div
<input type="text" value={ value } onChange={ this.handleChange }/
<p{ value }</p
</div
)
}
}
ReactDOM.render(
<Input/,
document.getElementById("example")
)
八、组件的生命周期
三种状态
- Mounting:已插入真实DOM
- Updating:正在被重新渲染
- Unmounting:已移出真实DOM
五种处理函数
- componentWillMount():在这个函数中,不可以调用setState来修改状态
- componentDidMount():①.ajax可以再这里调用,返回数据setState后组件会重新渲染;②.可以通过this.refs来访问真实DOM
- componentWillUpdate(object nextProps, object nextState)
- componentDidUpdate(object prevProps, object prevState)
- componentWillUnmount()
两种特殊状态
- componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用,该函数只监听props的改变,this.setState不会触发这个函数
- shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用,这个函数只返回true或false,表示组件是否需要更新
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29class Hello extends React.Component{
constructor(props){
super(props);
this.state = {opacity: 1.0};
}
componentDidMount(){
this.timer = setInterval(function () {
let opacity = this.state.opacity;
opacity -= .01;
if (opacity < 0.1){
opacity = 1.0
}
this.setState({
opacity: opacity
})
}.bind(this), 20)
}
render(){
return (
<div style={{ opacity: this.state.opacity }}
Hello { this.props.name }
</div
)
}
}
ReactDOM.render(
<Hello name="world"/,
document.getElementById('example')
)
九、Ajax
- 我们通常在componentDidMount周期中调用Ajax请求,成功后再用setState方法重新渲染数据
阮一峰老师的案例中使用的isMouted()方法,在React的ES6语法中已经废弃
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32class UserGist extends React.Component{
constructor(props){
super(props);
this.state = {
username: '',
lastGistUrl: ''
}
}
componentDidMount(){
this.serverReq = $.get(this.props.source, function (result) {
let lastGist = result[1];
this.setState({
username: lastGist.owner.login,
lastGistUrl: lastGist.html_url
})
}.bind(this))
}
componentWillUnmount() {
this.serverReq.abort();
}
render(){
return (
<div
{ this.state.username }'s last gist is <a href={ this.state.lastGistUrl }here</a
</div
)
}
}
ReactDOM.render(
<UserGist source="https://api.github.com/users/octocat/gists"/,
document.getElementById('example')
)
参考文章