0.两种组件的写法
类组件
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>
}
}
使用方法:<Welcome name="XXX">
函数组件
function Welcome (props){
return <h1>Hello, {props.name}</h1>
}
使用方法:<Welcome name="XXX">
相同与不同
- 标签都会被翻译成
React.CreateElement,根据传入值的类型不同来返回不同的结果。- 传入字符串,创建对应标签
- 传入函数,调用传入函数并获取其返回值
- 传入类,调用类的构造函数,获取一个组件对象,然后调用该对象的render函数,获取返回值
属性传递Props
类组件直接读取属性this.props.XXX
函数组件直接读取函数的参数props.XXX
数据状态State
类组件读使用this.state,写使用this.setState
函数组件使用[n, setN] = React.useState(初始状态)
注意点
React修改数据不会即时地更新UI,需要调用setState异步地更新UI。
不推荐在原有的对象上进行修改,一般参考setState({n:state.n+1})这种写法
复杂State的操作
类组件
React会自动合并第一层的属性,不需要额外操作
class Son extends React.Component {
constructor() {
super();
this.state = {
n: 0,
m: 0
};
}
addN() {
this.setState({ n: this.state.n + 1 });
}
addM() {
this.setState({ m: this.state.m + 1 });
}
render() {
return (
<div className="Son">
儿子 n: {this.state.n}
<button onClick={() => this.addN()}>n+1</button>
m: {this.state.m}
<button onClick={() => this.addM()}>m+1</button>
<Grandson />
</div>
);
}
}
但是不会合并第二层的对象,可以使用展开运算符将属性赋值到新对象上,然后改变数据
// Ojbect.assign会新建空对象,把之前的数据复制到空对象里
changeUser() {
const user = Object.assign({}, this.state.user);
user.name = "jack";
this.setState({
user: user
});
}
//...
changeUser() {
this.setState({
// m 和 n 不会被置空
user: {
...this.state.user, // 复制之前的所有属性
name: "jack"
// age 被置空
}
});
函数组件
不会自动合并
const Grandson = () => {
const [n, setN] = React.useState(0);
const [m, setM] = React.useState(0);
return (
<div className="Grandson">
孙子 n:{n}
<button onClick={() => setN(n + 1)}>n+1</button>
m:{m}
<button onClick={() => setM(m + 1)}>m+1</button>
</div>
);
};
const Grandson = () => {
const [state, setState] = React.useState({
n: 0,
m: 0
});
return (
<div className="Grandson">
孙子 n:{state.n}
<button onClick={() => setState({...state, n: state.n + 1 })}>n+1</button>
m:{state.m}
<button onClick={() => setState({...state, m:state.m + 1})</button>>
</div>
);
};
事件绑定
类组件的标准写法
class Son extends React.Component{
addN = () => this.setState({n: this.state.n + 1});
render(){
return <button onClick={this.addN}>n+1</button>
}
}
在声明时使用箭头函数并命名
典型错误
class Son extends React.Component{
addN(){
this.setState({n: this.state.n + 1})
}
addN: function(){
this.setState({n: this.state.n + 1})
}
}
-
正确写法的addN函数是对象本身的属性,意味着每个Son组件都可有自己的addN函数,例如,两个Son,每个都会有自己的addN函数。因为this指向Son组件
-
错误的addN函数是对象的共有属性,也就是原型上的属性,即prototype里面。意味着所有的Son组件共用一个addN函数。因为this指向全局变量window
区别
-
props是传递给组件的(类似于函数的形参),而state是在组件内被组件自己管理的(类似于在一个函数内声明的变量) -
props是组件的只读属性,组件内部不能直接修改props,要想修改props,只能在该组件的上层组件中修改 -
state是在组件中创建的,一般在constructor中初始化state -
state是可变的,是组件内部维护的一组用于反映组件UI变化的状态集合 -
state是多变的、可以修改,每次setState都异步更新的