组件(Component)
react中component是基本的单元, 所有的功能、代码都是封装在组件里面,包含html、js、css,通过React.Component 或者React.PureComponent等创建。
顺便延伸一下前端发展 component的概念(可能不准确), 印象中最早是ng里面的directive,再试polymer,web-component 再到vue react angular中的component就已经随处可见了。
state
react数据变化的基本单元之一,在当前组件使用,state变化,会触发render函数,重新渲染ui。
注意:
只能通过setState({state: ''}) 修改state,不能直接this.state = 'xxx'赋值;
setState可能是异步的,如果想立即拿到setState后的值, setState(obj, func) 第二个参数是一个函数回调,可以在回调函数中获取最新的this.state;
多次setState会被合并,触发一次render,在版本16.8之前是通过事务触发多个setState的合并更新,最新版是使用fiber;这块等后续有时间增加专门的源码分析补充细节原理吧。
class App extends React.Component {
constructor() {
super();
this.state = {name: 'react'}
}
render() {
const {name} = this.state;
return (
<div>
hello, {name}
</div>
)
}
}
props
和state组件类似,但是当前组件的props是不可变的,通过props完成组件的数据传递,
props类型可以是func、string、number等各种类型,通过PropTypes 控制校验类型,类型不匹配会跑出warning,注意:早期版本PropTypes是在react包中的,现在已经独立出来,需要单独安装引入'prop-types'。
defaultProps设置默认值,和propTypes设置的类型一致
如果想改变props,只能通过调用方修改。
按照经验,需要props频繁修改的一般都是在调用层都会抽象成state,通过setState 触发shouldComponentUpdate ---->render--->触发componentWillReceiveProps(新版本已经废弃) --->触发子组件render.
例子:
import PropTypes from 'PropTypes';
class App extends React.Component {
render() {
const {name} = this.props;
return (
<div>
hello, {name}
</div>
)
}
}
App.propTypes = {
name: PropTypes.string
};
App.defaultProps = {
name: 'test'
};
// 使用App
import App from './App';
class Container extends React.Component {
contructor() {
this.state = {name: 'react'};
}
render() {
const {name} = this.state;
return (
<div><App name={name}/></div>
)
}
}
jsx(javascript and xml)
jsx其实就是一个javascript的语法扩展,类似模板语言,但是包括javascript全部功能,react开发并不强制要求使用jsx,但是还是使用jsx开发react,更合理,效率更高。
我们来看一下jsx的例子:
const name = 'jsx first';
const url = ''
const func = (name) => { 'hello, ' + name};
const element = <div>Hello, {func(name)}, <img src={url}/></div>;
jsx 支持函数调用、变量命名,属性传递等。
这里要顺便提一下, 通过babel 最终会将jsx转成js
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
// 转成
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
事件
react事件是根据w3c标准,自定义了事件机制,所有的事件都绑定在document上,统一分发,使用者不用关心浏览器兼容问题。
使用react事件主要需要关注几点:
- event是事件合成事件概念,包含了浏w3c标准的事件功能,具体可以参考SyntheticEvent.js
- js的class方法不会默认绑定this,需要手动绑定
- 命名使用驼峰的规则
事件调用有3中方式(主要还是为了解决this问题)
方法一:在constructor中手动绑定this, 需要手动绑定,没什么别的问题,就是代码比较啰嗦
class App extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// 为了在回调中使用 `this`,这个绑定是必不可少的
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(state => ({
isToggleOn: !state.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
方法二:虽然不需要在手动bind this了,但是每次调用render都会创建不同的回调函数,如果该回调函数作为 prop 传入子组件时,这些组件可能会进行额外的重新渲染。不推荐使用这种方式
class App extends React.Component {
handleClick(e) {
console.log(this, e);
}
render() {
// 此语法确保 `handleClick` 内的 `this` 已被绑定。
return (
<button onClick={(e) => this.handleClick(e)}>
Click me
</button>
);
}
}
方法三:react文档的术语是使用class fields绑定this,其实就是在具体方法使用箭头函数。推荐使用这种方式
class App extends React.Component {
// 此语法确保 `handleClick` 内的 `this` 已被绑定。
handleClick = () => {
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}
生命周期

上图很好的描述了react生命周期执行的顺序,和state改变后执行的过程。
重点关注的几个:
- componentDidMount, 一般后端数据请求在此处触发
- render,state/props变化以后触发页面渲染
- shouldComponentUpdate,return false的话,则不继续执行,可以在这里进行性能优化,减少不必要的渲染
- componentWillUnmount,在组件卸载的时候手动做一些处理,比如remove一些手动绑定的事件,clearInterval等
16.3之后的生命周期,废弃三个生命周期函数
componentWillMountcomponentWillReceivePropscomponentWillUpdate
增加两个新的生命周期
- static getDerivedStateFromProps
- getSnapshotBeforeUpdate
