如何创建Class组件
ES5方式(已过时)
import React from 'react';
const A = React.createClass({
render(){
return (
<div>hi</div>
)
}
})
export default A
因为ES5不支持class,才会有这种方式。
ES6方式
import React from 'react';
class B extends React.Component {
constructor(props){
super(props);
}
render(){
return (
<div>hi</div>
)
}
}
export default B;
以后创建类只用ES6方式,现在还有很多代码是用ES5,即还在搞IE8,如果需要维护就用webpack + babel 将ES6翻译成ES5即可。
Props
作用
- 接受外部数据,且只能读不能写,外部数据由父组件传递。
- 接受外部函数,在恰当的时机,调用该函数,该函数一般是父组件的函数。
事例
Parent父组件:
class Parent extends React.Component {
constructor(props){
super(props)
this.state = {name:'frank} //声明外部数据
}
onClick = () => {}
render(){
return <B name={this.state.name} //把外部数据传入到子组件B
onClick={this.onClick}>hi</B> //注意,这个this.onClick传给B组件的是一个地址
}
}
上面的代码里的第八行,外部数据( <B name={this.state.name onClick={this.onClick}>hi</B>}
),被包装成一个对象,如果打印到控制台可以看到 {name:'frank',onClick:...,children:'hi'}
,注意,此处的onClick是一个回调。
B在组件:
class B extends React.Component {
constructor(props){
super(props);
}
render(){}
}
上面的第1行至第3行是固定代码,其中第2行代码与第3行代码是固定搭配,如果不需要引用外部数据可以不写,但是一旦写了就要补全代码不能漏。
根据上面父组件里“传给B组件的是一个地址”的代码注释提示可知, this.props
是一个外部数据的地址。
如何读取外部数据
通过 this.props.xxx
读取如:
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>
}
}
如何写外部数据
:::danger 禁止写外部数据 :::
理由:这涉及到了React的哲学思想,原则上是应该由数据的主人对数据进行更改!
根据传过来的地址,改外部数据也只会改那个旧的对象的值,并不是新的对象的值,以下代码不推荐:
this.props = {/*另一个对象*/} //改props的值(一个地址)
this.props.xxx = 'hi' //改props的属性
既然是外部数据,就不应该从内部改值。
Props的相关钩子
:::tips
钩子是什么?
可以在生命周期执行的函数
:::
componentWillReceiveProps钩子(已被弃用)
作用:当组件接受新的props时,会触发此钩子。
现在已经被弃用,并更改为 UNSAFE_componentWillReceiveProps
总而言之,这个钩子就不用了,只会在维护旧代码才会看到。
State 与 setState
即内部数据
如何初始化State
如下:
class B extends React.Component {
constructor(props){
super(props);
this.state = {
user: {name: 'frank', age:19}
}
}
render(){ /*...*/}
}
读写内部数据
- 读:用
this.state
,如:this.state.xxx.yyy.zzz
。 - 写:用
this.setState(???,fn)
,如this.setState(newState,fn)
如:
class App extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
n: 1
}
}
onClick = () => {
this.setState(state => ({n: this.state.n + 1})) //写
}
render(){
return (
<div>
{this.state.n} //读
<button onClick={this.onClick}> +1 </button>
</div>
)
}
}
注:
- 写有两个参数,第二个参数可不写,第二个参数的作用是:在完成写数据的时候就会执行该函数。
- 在
setState
时是不会立即改变this.state
,会在当前代码运行完成后,才去更新this.state
,从而触发UI更新。
根据上面注意的第二条,可以进行改良,不使用对象的形式而是使用函数的形式,如下:
class App extend React.Component {
constructor(props){
super(props);
/*...*/
}
onClick = () => {
this.setState((state) => ({n: this.state.n + 1})) //写
}
render(){
return (
/*...*/
)
}
}
这种方式就是,当我想算的时候就会去执行,而不是对象的写法,需要代码运行完成才可以执行。
setState时会 shallow merge
即setState会自动将新state与旧state进行一级合并。
能修改this.state吗
能,但这是不守规矩!如:
this.state.n += 1
this.setState(this.state)
并没有人说不可以这样,虽然可以但这只是不遵守规矩的行为,请避免。