一 ES6创建方式
import React from 'react';
class App extends React.Component{
constructor(props) {
super(props);
this.state={n:1}
}
add=()=>{
this.setState((state)=>{
return {n:state.n+1}
},()=>{
//打印的是更新后的state
console.log('回调'+this.state.n);
})
//打印的是旧的state
console.log('立即'+this.state.n);
}
render(){
return (
<div>
<div>{this.state.n}
<button onClick={this.add}>加一</button>
</div>
<B name={this.state.n} />
</div>
)
}
}
class B extends React.Component{
// componentWillReceiveProps(nextProps, nextContext) {
// console.log('旧的'+this.props.name);
// console.log('更新了');
// console.log('新的'+nextProps.name);
// }
render() {
return(
<div>{this.props.name}</div>
)
}
}
二 props
- props的作用
(1) 接收外部数据
只能读不能写,外部数据由父组件传递。
(2) 接收外部函数
在恰当的时机,调用该函数。该函数一般是父组件的函数。
- 读props,构造函数中写了super(props)之后,this.props就是外部数据对象的地址了,直接使用this.props.x就可以访问x属性了。
- 当接收props变化时,会触发componentWillReceiveProps钩子,该钩子已被弃用。
三 state
//初始化
this.state={n:1}
//读state
this.state.n
//写
this.setState(newState,fn)或this.setState((state,props)=>newState,fn)
//setState不会立即改变this.state,会在当前代码执行完后,再去更新this.state,从而触发UI更新
//setState写时会进行shallow merge,会自动将xinstate与旧state进行一级合并,而函数组件则完全不会自动合并
//fn会在写入成功后执行
四 生命周期
- constructor
//初始化state,props,以及bind this
constructor(props){
super(props);
}
- render
//展示视图
//里面可以直接写if else,但不能直接写for循环,需要用到数组,例如array.map
const add=()=>{}//写到constructor外面,并且用箭头函数,可以避免this改变的问题
render(){
return(
<React.Fragment>
<div>{n}</div>
<div onClick={this.add}>1</div>
</React.Fragment>
)
}
- componentDidMount
//在元素插入页面后执行代码,这些代码依赖DOM。
//比如想获取div的宽度就可以在这里写。
//官方推荐,在这里发起加载数据的ajax请求
//首次渲染会执行此钩子
//获取div宽度
class App extends React.Component{
constructor(props) {
super(props);
this.state={n:1};
//创建引用,下一步需要关联到div上
this.divRef=React.createRef();
}
componentDidMount() {
const {width}=this.divRef.current.getBoundingClientRect();
console.log(width);
}
render(){
return (
<div>
<div ref={this.divRef}>{this.state.n}
<button >我是按钮</button>
</div>
</div>
)
}
}
- shouldComponentUpdate
//允许我们手动判断组件是否需要更新,我们可以根据应用场景灵活的设置返回值,以避免不必要的更新
//返回true表示不阻止组件更新,返回false表示阻止组件更新
//旧对象是{n:1},新对象也是{n:1},
//但由于这两个对象地址不同,因此React认为数据不同数据变了,
//从而需要重新render,对比新虚拟DOM和上次虚拟DOM的不同,
//虽然对比结果是值相同不需要更新UI,但还是多了执行render和对比DOM的过程。
//因此我们可以使用shouldComponentUpdate,手动判断
class App extends React.Component{
constructor(props) {
super(props);
this.state={n:1};
}
add=()=>{
this.setState(state=>({n:state.n+1}));
this.setState(state=>({n:state.n-1}));
}
shouldComponentUpdate(newProps,newState){
if(newState.n===this.state.n){
return false;
}else{
return true;
}
}
render(){
console.log('渲染了')
return (
<div>
<div>{this.state.n}
<button onClick={this.add}>我是按钮</button>
</div>
</div>
)
}
}
//React.PureComponent可以代替React.Component
//它会在 render 之前对比新 state 和旧 state 的每一个 key,以及新 props 和旧 props 的每一个 key。
//如果所有 key 的值全都一样,就不会 render;如果有任何一个 key 的值不同,就会 render。
- componentDidUpdate
//在视图更新后执行代码
//此处也可以发起ajax请求,用于更新数据
//比如userID变了,需要获取新的数据,就要在componentDidUpdate里面发起ajax请求。
//首次渲染不会执行此钩子
//在此处setState可能会引起无限循环,除非添加if条件判断
//若shouldComponentUpdate返回false,则不会触发此钩子
- componentWillUnmount
//组件将要被移除页面然后被销毁时执行的代码
//unmount过的组件不会再次mount
//在unmount之前,监听的时间,创建的Timer,AJAX请求都要取消