创建class的方式(推荐ES6)
import React from 'react';
class B extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
hi
)
}
}
export default B;
- 第二三四行可以直接删掉,如果要在里面加额外的代码,就写;如果只有这三行就可以省掉。
props(外部数据)
初始化
class B extends React.Component{
constructor(props){
super(props)
}
render(){}
}
要么不初始化,即不写constructor
要么初始化,且必须写全套(不写super直接报错)
效果:这么做了之后,this.props就是外部数据对象的地址了
读外部数据
class B extends React.Component {
constructor(props) {
super(props);
}
render(){
return <div onClick={this.props.onClick}>
{this.props.name}
<div>
{this.props.children}
</div>
</div>
}
}
//通过this.props.xxx 读取
- 永远不许写props
相关钩子
export default class App extends React.Component {
constructor(props){
super(props)
this.state = {
x:1
}
}
onClick = ()=>{
this.setState((state)=>{
return {x:state.x+1}
})
}
render(){
return (
<div className="App">
App <button onClick={this.onClick}>+1</button>
<B n={this.state.x}/>
</div>
);
}
}
class B extends React.Component{
componentWillReceiveProps(newProps){
console.log('旧的 props 为')
console.log(this.props)
console.log('新的 props 为')
console.log(newProps)
// 注意 console 的延迟计算 bug
}
render(){
return <div>B {this.props.n}</div>
}
}
componentWillReceiveProps钩子
-
当组件接受新的props时,会触发此钩子
-
啥是钩子?黑话,将其翻译成【特殊函数】即可
-
该钩子已被弃用,更名为
UNSAFE_componentWillReceiveProps,不要使用该钩子
props 的作用
接受外部数据
-
只能读不能写
-
外部数据由外组件传递
接受外部函数
-
在恰当的时机,调用该函数
-
该函数一般是父组件的函数
State & setState(内部数据)
初始化State
class B extends React.Component{
constructor(props) {
super()
this.state = {
user: {name: 'frank', age:18}
}
}
render() { /*...*/}
}
读写State
读用this.state
this.state.xxx.yyy.zzz
写用this.setState(???,fn)
-
this.setState(newState,fn) -
注意setState不会立刻改变this.state,会在当前代码运行完后,再去更新this.state,从而触发UI更新
-
this.setState((state,props)=>newState,fn),这种方式的state反而更易于理解,fn会在写入成功后执行
- 推荐第二种写法
写时会shallowmerge
- setState会自动将新state与旧state进行一级合并(React 只会检查新 state 和旧 state 第一层的区别,并把新 state 缺少的数据从旧 state 里拷贝过来)
修改this.state的属性值(不推荐用)
-
this.state.n +=1 -
this.setState(this.state)
生命周期
函数列表
-
constructor()-- 在这里初始化state -
static getDerivedStateFromProps()
-
shouldComponentUpdate()-- return false阻止更新(不要忘了return true) -
render()-- 创建虚拟DOM -
getSnapshotBeforeUpdate()
-
componentDidMount()-- 自减已出现在页面 -
componentDidUpdate()-- 组件已更新 -
componentWillUnmount()-- 组件将死 -
static getDerivedStateFromError()
-
componentDidCatch()
constructor
shouldComponentUpdate
用途
-
返回true表示不阻止UI更新
-
返回false表示阻止UI更新
class App extends React.Component {
constructor(props) {
super();
this.state = {
n: 1,
};
}
onClick = () => {
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('render 了一次')
return (
<div>
{this.state.n}
<button onClick={this.onClick}>+1-1</button>
</div>
)
}
}
React.PureComponent
- PureComponent 会在 render 之前对比新 state 和旧 state 的每一个 key,以及新 props 和旧 props 的每一个 key。如果所有 key 的值全都一样,就不会 render;如果有任何一个 key 的值不同,就会 render。
render
用途
-
展示视图
return (<div>...</div>) -
只能有一个根元素
-
如果有两个跟元素,就要用
<React.Fragment>包起 -
<React.Fragment/>可以缩写成<></>
技巧
- render里面可以写
if...else
render() {
let message;
if (this.state.n % 2 === 0) {
message = <div>偶数</div>;
} else {
message = <span>奇数</span>;
}
return (
<>
{message}
<button onClick={this.onClick}>+1</button>
</>
);
}
- render里面可以写?:表达式(或者&&)
render() {
return (
<>
{this.state.n % 2 === 0 ?
<div>偶数</div>:
<span>奇数</span>}
<button onClick={this.onClick}>+1</button>
</>
);
}
render() {
return (
<>
{this.state.n % 2 === 0 && <div>偶数</div> }
<button onClick={this.onClick}>+1</button>
</>
);
}
}
- render里面不能直接写for循环,需要用数组
- render里面可以写array.map (循环)
所有的循环必须写key
componentDidMount()
用途
-
在元素插入页面后执行代码,这些代码依赖DOM
-
比如你想获取div的高度,就最好在这里写
-
此处可以发起加载数据的AJAX请求(官方推荐)
-
首次渲染会执行此钩子
建议用divRef的时候先声明divRef = undefined
componentDidUpdate()
用途
-
在视图更新后执行代码
-
此处也可以发起AJAX请求,用于更新数据
-
首次渲染不会执行此钩子
-
在此处setstate可能会引起无线循环,除非放在if里
-
若shouldComponentUpdate返回false,则不触发次钩子
componentWillUnmount
用途
-
组件将要被移出页面然后被销毁时执行代码
-
unmount过的组件不会再次mount