写法
1、函数组件
function Welcome(props){
return <h1> Hello,{props.name} </h1>
}
使用:<Welcome name='frank'/>
2、类组件
class Welcome extends React.Component {
render(){
return <h1> Hello,{this.props.name} </h1>
}
}
使用:<Welcome name='frank' />
组件逻辑
- 翻译过程
1、会被翻译为 React.createElement('div');
2、 会被翻译为 React.createElement(Welcome);
3、可在Babel online上查看翻译结果
- React.createElement 的逻辑 1、如果传入一个字符串 'div',则会创建一个 div;
2、如果传入一个函数,则会调用该函数,获取其返回值;
3、如果传入一个类,则在类前面加个 new(这会执行 constructor),获取一个组件对象,然后调用对象的render 方法,获取其返回值。
读写数据
- 添加 state (内部数据) 1、代码示例
2、类组件:this.state读数据,this.setState写数据;
3、函数组件:const [n,setN] = React.useState(0)返回数组,第一个参数 n 读,第二个参数 setN 用来写,useState()括号中的是初始值。
- 添加 props(外部数据) 1、代码示例
2、类组件直接读取属性 this.props.xxx;
3、函数组件直接读取参数 props.xxx
注意事项
- 类组件注意事项 1、React 没有像 Vue 监听 data 一样监听 state,当 this.state.n +=1 时,其实 n 已经改变了,只不过 UI 不会自动更新而已,调用 setState 才会触发 UI 更新(一部更性);
2、setState 之后,state 不会马上改变,立马读 state 会失败,更推荐的方式是 setState(函数);
//n 的初始值为0;
add(){
this.setState({n:this.state.n+1}) //n 为 1
coonsole.log(this.state.n) // 打印 0
}
//用setState(函数):
add(){
this.setState(state=>{
const n = state.n + 1 //n 为 1
console.log(n) //打印 1
return {n}
})
}
3、this.setState(this.state) 不推荐,React 希望我们不要修改旧 state(不可变数据),常用代码:setState({n:state.n+1})
- 函数组件注意事项 1、跟类组件类似的地方:也要通过 setX(新值) 来更新 UI;
2、更类组件不同的地方:没有 this,一律用参数和变量。
复杂 state
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(){
<div>
n:{this.state.n}
<button onClick = { ()=>{this.addN()} }>+1</button>
m:{this.state.m}
<button onClick = { ()=>{this.addM()} }>+1</button>
</div>
}
const GrandSon = ()=>{
const [n,setN] = React.useState(0)
const [m,setM] = React.useState(0)
return (
<div>
n:{n}
<button onClick=()=>{setN(n + 1)}>n+1</button>
m:{m}
<button onClick=()=>{setM(m + 1)}>m+1</button>
</div>
)
}
- 函数组件 m 被置空 点击 n ,m 会变成 NaN
const GrandSon = ()=>{
const [state,setState] = React.useState({
n:0,
m:0
})
return(
<div>
n:{state.n}
<button onClick = {()=>setState({n:state.n+1})}> n+1 </button>
m:{state.m}
<button onClick = {()=>setState({m:state.m+1})}> m+1 </button
</div>
)
}
class Son extends React.Component {
constructor(){
super()
n:0,
m:0,
user:{
name:'frank',
age:18
}
}
addN(){
this.setState({n:this.state.n + 1})
}
changeUser(){
this.setState({
//m 和 n 不会被置空
user:{
name:'jack'
// age 被置空
}
})
}
render(){
<div>
n:{this.state.n}
<button onClick={()=>this.addN()}>n+1</button>
<hr/>
<div>user.name:{this.state.user.name}</div>
<div>user.age:{this.state.user.age}</div>
<button onClick={() => this.changeUser()}>change user</button>
</div>
}
}
- 用 ... 操作符,或 Object.assign,使 m 不被置空
changeUser(){
this.setState({
//m 和 n 不会被置空
user:{
...this.state.user
name:'jack'
// age 被置空
}
})
}
changeUser(){
const user = Object.assign({},this.state.user)
user.name = 'jack'
this.setState({
user:user
})
}
- 总结 1、类组件的 setState 会自动合并第一层属性;
2、但是不会合并第二层属性;
3、使用 Object.assign 或 ...操作符;
4、函数组件的 setX 则完全不会自动合并,必须用 ...操作符合并
事件绑定
-
事件绑定写法
-
两种写法区别 1、蓝色函数(箭头函数)是对象本身的属性,这意味着每个 Son 组件都有自己的 addN,如果有两个Son,就有两个 addN;
2、红色函数是对象的公用属性,也就是原型上的属性,这意味这所有 Son 组件公用一个 addN;
3、以下代码可证明:
class Person2 {
sayHello = ()=>{}
}
相当于:
class Person2 {
constructor(){
this.sayHello = ()=>{}
}
}
- 为什么 this 会变/不会变 1、所有函数的 this 都是参数,由调用决定,所以可变;
2、唯独箭头函数的 this 不变,因为箭头函数不接受 this 作为参数,箭头函数的 this 是定义的时候确定,后面就不能再改了。
this 例题
var a = {
name:"里面的name",
sayName:function(){
console.log('this.name' + this.name)
}
}
var name = '外面的name'
function sayName(){
var sss = a.sayName
sss() // sss.call() ---> this 是 window,打印‘外面的name ’
a.sayName() //a.sayName.call(a) --->this 是 a,打印‘里面的name’
(a.sayName)() //a.sayName.call(a) --->this 是 a ,打印‘里面的name’
(b = a.sayName)() //b.call() --->this 是 window , 打印‘外面的name’
}
sayName() //sayName.call() --->call 的第一个参数为空,所以 this 为 null ,null 自动替换为 window ,所以这里的 this 就是 window
var length = 10
function fn(){
console.log(this.length)
}
var obj = {
length:5,
method:function(fn){
fn() // fn.call() --->this 是 window , 打印 10
arguments[0]() // arguments[0].call(arguments),this 是 arguments,也就是 [fn,1],数组长度为2 ,所以打印 2
}
}
obj.method(fn,1) //obj.method.call(obj,arguments[fn,1]] ,this 是 obj
React V.S. Vue
- 相同点 1、都是对视图的封装,React 是用类和函数表示一个组件,而 Vue 是通过构造选项构造一个组件;
2、都提供了 createElement 的 XML 简写,React 提供的是 JSX 语法,而 Vue 提供的是模板语法(v-for/v-if...)
- 不同点 React 是把 HTML 放在 JS 里写(HTML in JS),而 Vue 是把 JS 放在 HTML 里写(JS in HTML)