组件 Component
Element V.S Component
元素与组价
-
const div = React.createElement('div', ...), 这是一个React元素(d小写) -
const Div = () => React.createElement('div', ...),这是一个React组件(D大写)
什么是组件?
-
能跟其他的物体组合起来的物件,就是组件
-
组件并没有明确的定义,靠感觉理解就行
-
就目前而言,一个返回React元素的函数就是组件
-
在Vue里,一个构造选项就可以表示一个组件
React两种组件
一、函数组件
function Welcome(props) {
return <h1>Hello, {props.name}</h1>
}
使用方法: <Welcome name="frank"/>
二、类组件
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>
}
}
使用方法: <Welcome name="frank"/>
会被翻译成什么?
-
<div/>会被翻译为React.createElement('div') -
<Welcome/>翻译为React.createElement(Welcome)
React.createElement的逻辑
-
如果传入一个字符串
'div', 则会创建一个div -
如果传入一个函数,则会调用该函数,获取其返回值
-
如果传入一个类,则在类前面加上
new(这会导致执行constructor),获取一个组件对象,然后调用对象的render方法,获取其返回值
class Welcome extends React.Component{
constructor(){
super()
this.state = {n:0}
}
render(){
return <div>hi</div>
}
}
代码示例
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) //析构函数
// 等价于
// const array = React.useState(0)
// const n = array[0]
// const setN = array[1]
//意思为声明一个state,state初始值为0,用n代表0,setN对0进行修改,setN之后就会得到一个新的n
return (
<div className="Grandson">
孙子 n: {n}
<button onClick = {()=> setN(n + 1)}> +1 </button>
</div>
)
}
const rootElement = document.getElementById("boot")
ReactDOM.render(<App />, rootElement)
添加props(外部数据)
import React from "react"
import ReactDOM from "react-dom"
import "./styles.css"
function App() {
return (
<div className="App">
爸爸
<Son messageForSon="儿子你好"/>
</div>
)
}
class Son extends React.Component{
render(){
return (
<div className="Son">
我是儿子,爸爸对我说 [{this.props.messageForSon}]
<Grandson messageForGrandson="孙子你好" />
</div>
)
}
}
const Grandson = props =>{
return (
<div className="Grandson">
我是孙子,我爸对我说 [{props.messageForGrandson}]
</div>
)
}
const rootElement = document.getElementById("root")
ReactDOM.render(<App />, rootElement)
<Son messageForSon="儿子你好"/>如果穿的字符串可以直接用" ",如果用的是变量,用{ }
类组件直接读取属性this.props.xxx
函数组件直接读取参数props.xxx
添加state(内部数据)
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})
//等价于
//this.setState((state)=>{
// return {n: state.n + 1}
// })
//等价于
this.setState(state=>{
const n = state.n + 1
return {n}
//setState是等会改变n
})
}
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>
//setN永远不会去改变n,会产生一个新的n
)
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
- 类组件用
this.state读,this.setState写,建议用函数的方式写
this.setState = (state=>{
const n = state.n + 1
return {n} //{n:n}
})
- 函数组件用
useState返回数组,第一项读,第二项写
类组件注意事项
this.state.n +=1 无效?
-
其实
n已经改变了,只不过UI不会自动更新而已 -
调用
setState才会触发UI更新(异步更新) -
因为
React没有像Vue监听data一样监听state
setState会异步更新UI
-
setState之后,state不会马上改变,立马读state会失败 -
更推荐的方式是
setState
this.setState(this.state)不推荐
-
React希望我们不要修改就
state(不可变数据) -
常用代码:
setState({n:state.n+1})
总结: 这是一种函数式理念
函数组件注意事项
跟类组件类似的地方
- 也要通过
setX(新值)来更新UI
跟类组件不同的地方
- 没有
this,一律用参数和变量
两种编程模型
复杂的state
state里面不止只有n,若还有m
- 类组件代码
class Son extends React.Component {
constructor() {
super();
this.state = {
n: 0,
m: 0
};
}
addN() {
this.setState({ n: this.state.n + 1 });
// m 会被覆盖为 undefined 吗?
}
addM() {
this.setState({ m: this.state.m + 1 });
// n 会被覆盖为 undefined 吗?
}
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>
);
}
}
- 函数组件代码
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>
);
};
- 不推荐写法
如果想上面那样写就:
总结:
-
类组件的setState会自动合并第一层属性,但是并不会合并第二层属性
-
如果想要合并怎么办?使用
Object.assign或者...操操作符 -
函数组件的setX则完全不会帮你合并,要合并自己用
...操作符合并
事件绑定
类组件的事件绑定
回答
- 蓝色和红色的区别
蓝色函数本身的属性,这意味着每个Son组件都有自己的addN,如果有两个Son,就有两个addN
红色函数是对象的公用属性(也就是原型上的属性),这意味着所有Son组件共用一个addN
- 为什么this会变/不变
所有函数的this都是参数,由调用决定,所以可变
唯独箭头函数的this不变,因为箭头函数不接受this