React组件分两种:
- 函数组件
- 类组件
函数组件
function Weblcome(props) {
return <h1>Hello,{props.name}</h1>
}
使用方法: <Welcome name="frank">
,而 name="frank"
为外部传入组件的数据。
类组件
class Welcome extends React.Component {
render() {
return <h1>Hello,{this.props.name}</h1>
}
}
使用方法: <Welcome name="frank">
,而 name="frank"
为外部传入组件的数据。
组件翻译
<Welcome />
会被翻译成什么?
注意,在React里,写类似这种 <div />
,这不是HTML!!!
<div />
会被翻译成React.createElement('div')
,div是个虚拟DOM!- 与
<div />
不同的是,因为<Welcome />
是函数组件,会被翻译成React.createElement(Welcome)
。
看出来:
React.createElmenet()
可以接受字符串和函数。- 如果传入一个字符串’div’,则会创建一个div。
- 如果传入一个函数,则会调用该函数,获取其返回值。
- 如果传入一个类,则会在类的前面加个
new
(这会导致执行才constructor),获取一个组件对象,然后调用对象的render方法,获取其返回值。
还有个翻译器可以翻译:翻译器
props和state
props是外部数据,state是内部数据!
props
- 类组件会直接读取属性
this.props.xxx
- 函数组件读取直接读取参数
props.xxx
如下:
类组件的props
函数组件的props
state
- 类组件使用
this.state
读,this.setState
写,setState
会异步改变n的值。 - 函数组件用
useState
返回数组,第一项读,第二项写,useState
不会改变n的值。
如:
类组件
函数组件
setState注意事项
this.state.n += 1
是无效的。实际上n已经改变,只不过UI并不会自动更新,需要调用setState才会触发UI更新(异步更新),这和Vue的不同,Vue还可以监听data一样,而React没有。
setState会异步更新UI。
所以,setState之后,state是不会马上改变的,在还没执行完之后的代码,读取值依旧是旧值,所以需要等待剩下的代码执行完毕后state才会改变。
this.setState(this.state)
不推荐需要了解React一个思想,React是不推荐更改以前的旧值,而是创建一个新的对像,这和Vue相反!所以不要修改state(不可变数据)。
state复杂情况处理
如果state里有n和m
类组件的写法:
函数组件:
需要注意的是:类组件的setState会自动合并第一层属性,但不会合并第二层属性,而函数组件都不会自动合并属性。解决办法是使用扩展运算符 ...
合并属性。
事件绑定的写法
类组件:
<button onClick={()=> this.addN()}> n+1 </button> //可以这么写
<button onClick={()=> this.addN}> n+1 </button> //不能这么写,这里的this变成window
<button onClick={()=> this.addN.bind(this)}> n+1 </button> //可以但还不如第一条
this._addN = () => this.addN()
<button onClick={()=> this._addN}> n+1 </button> //这个可以,但是需要想一个名字,以下改良
以下是改良后的代码
constructor(){
this.addN = () => this.setState({n: this.state.n + 1})
}
render(){
return <button onClick={this.addN}> n+1 </button>
}
改良后好了很多,但React的团队看了之后干脆出了个语法糖,也就是最终的写法:
class Son extends React.Component{
addN = () => this.setState({n: this.state.n + 1}); //可以写在外面了!效果与上面的改良后代码没区别
render(){
return <button onClick={this.addN}> n+1 </button>
}
}
小试牛刀
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App(){
return (
<div className="App">
爸爸
<Son />
</div>
)
}
class Son extends React.Component{
constructor(){
super();
this.state = {
n: 0
}
}
add(){
this.setState({n: this.state.n + 1});
}
render(){
return (
<div className="Son">
儿子 n:{this.state.n}
<button onClick={() => this.add()}>+1</button>
<Grandson/>
</div>
)
}
}
const Grandson = () => {
const [n, setN] = React.useState(0);
return (
<div className="Grandson">
孙子 n:{n}
<button onClick={() => setN(n + 1)}> +1 </button>
</div>
)
}
const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);