01-3 React组件(类组件、函数组件、props、state)

目录

  • 类组件和函数组件
  • 如何使用 props 和 state
    外部数据和内部数据,对应Vue的props 和 data
  • 如何绑定事件
  • 复习this

1.组件 component

1.1 Element 和 component

  • const div = React.createElement('div',...)
    这是一个React元素(d小写)
  • const Div = ()=> React.createElement('div',...)
    这是一个React组件(D大写)

1.2 什么是组件

  • 能跟其他物件组合起来的物件,就是组件
  • 在React中,一个返回 React元素 的 函数就是组件
  • 在Vue中,一个构造选项就可以表示一个组件
    data、method、template、render

1.3 React两种组件(函数组件和类组件)

  • 一般推荐使用函数组件,类组件已经过时了
  • 一、函数组件
    使用方法:<Welcome name="frank" />
    1.组件当标签用,所有函数组件的第一个参数都可以接收一个外部数据
    2.name="frank"会自动变成props的keyvalue
function Welcome(props){
  //相当于 return 一个 React.creareElement
  return <h1>Hello, {props.name}</h1>
}
  • 二、类组件
    使用方法:<Welcome name="frank" />
    props需要在this上面取拿
class Welcome extends React.Component{
  render(){  // render 渲染组件视图
    return <h1>Hello, {this.props.name}</h1>
  }
}

1.4 <Welcom />

  • React 中的这种标签不是在写HTML
  • babel 就把 XML 语法翻译为JS语法
  • <div className="red" />会被 babel 翻译为:React.createElement('div',{className="red"})
    如果是原生的标签,则会变成字符串
  • <Welcome/>会被翻译为:React.createElement(Welcome,{})
    如果是自定义的组件,后面的welcome就是函数

1.5 React.createElement的逻辑

  • 如果传入一个字符串 ‘div’,则会创建一个 div(虚拟DOM元素)
  • 如果传入一个函数,则会调用该函数,获取其返回值
    1.如传入Welcome函数,就会调用这个函数,然后获取它return的值
    2.返回值会代替原来标签的位置,<Welcom />就不存在了
  • 如果传入一个类,则在类前面加个 new
    1.这会导致执行 constructor对应函数,获取一个组件对象
    2.然后调用对象的 render 方法,获取其返回值(重点还是获得其返回值)
    3.constructor 就是 new 对应的函数
    4.要初始化 state 就要在 constructor(构造函数)里面初始化
class Welcome extends React.Component{
  constructor(){
    super()
    this.state={n:0}
  }
  add(){},
  render(){
    return <h1>Hello, {this.props.name}</h1>
  }
}

2.案例

  • 代码
  • 一个小tip:析构函数
    const [n, setN] = React.useState(0);
    声明一个变量为0,然后对它进行读(n)和写(setN)
    setN之后就会得到一个新的n,而不是改变原有的n

2.1 函数组件和类组件使用 props(外部数据)

  • 外部数据只能:读
  • 传递:messageFor+组件名=‘字符串’/{变量}
    <Son messageForSon="儿子你好"/{1+1} />
  • 子类组件直接读取属性:this.props.xxx
    {this.props.messageForSon}
  • 函数子组件直接读取传入的参数props:props.xxx
const Grandson = (props)=>{
  return (
    <div>{props.messageForSon}</div>
  )
}
  • 外部数据只能读,不能写

2.2 函数组件和类组件使用 state(内部数据)

  • state也就是 Vue 的data
  • state的最重要的三点:初始值、读、写
  • 类组件
    1.直接写在 constructor里面:this.state = {n:0}
    2.读取:this.state.n
    3.写:this.setState({ n : this.state.n + 1})
    ——使用setState的时候对象要重写一遍
    ——为什么不直接在原来的上面改?
    ——React的思想,数据不可变,要变就产生新的对象
    4.在之前的Vue中可以直接变化n,因为Vue会监听n的变化然后刷新UI,但React没有监听n,因此不能直接修改n
    5.那么如何告诉React我修改了数据:使用 this.setState(新对象)
add() {
  // this.state.n += 1 为什么不行
  this.setState({ n: this.state.n + 1 });
}
  • 类组件:setState的更优写法:this.setState(函数)
    问题:setState是一个异步更新UI的过程,它会等整个add函数代码运行完才更新n,如果add中有其他对n的操作,就没办法对最新的n值操作
    解决:this.setState 接收一个函数,这个函数就是对 state的操作,然后返回新的state值(原来是直接接受新state对象)
add(){
  this.setState((state)=>{
   //接收旧的state,返回新的state
    const n = state.n+1 //获取新的n
    console.log(n)//操作最新的n
    return {n}
  })
}
  • 函数组件:React.useState 返回数组(只有两项)
    const [n, setN] = React.useState(0);
    1.返回的第一项读,第二项写(一般用析构简写)
    2.用的时候给一个初始值就行
    3…setN永远不会改变n,会产生一个新的n
const n = React.useState(0)[0]
const setN = React.useState(0)[1]

2.3 类组件注意事项

  • this.state.n += 1 无效
    1.其实n已经改变,只不过UI不会自动更新而已
    2.调用setState才会触发 UI 更新(异步更新)
    3.因为 React 没有像 Vue 监听 data 一样监听 state
  • setState 会异步更新UI
    1.setState之后,state 不会马上改变,立马读 state 会读旧的
    2.更推荐:setState(函数)
  • this.setState(this.state) 可行但不推荐
    1.也就是说我们修改了旧的state,然后再次将旧state传给setState是可行的
    2.但React希望我们不要修改旧state(不可变数据)
    3.常用代码:setState({n:state.n+1})

2.4 函数组件

  • 使用 setX(新值) 来更新UI
  • 跟类组件不同的地方:没有this
    一律使用参数和变量

3.两种编程模型
在这里插入图片描述

  • Vue的编程模型:对数据的修改,会直接映射到UI上面
    1.一个对象对应一个虚拟DOM
    2.当对象属性改变时,把属性相关的DOM节点全部更新
    3.如当n发生变化,则Vue把n出现的地方全部重新渲染
  • React的编程模型:不能修改之前的数据,直接新建一个数据对象
    1.一个对象对应一个虚拟DOM
    2.另一个对象,对应另一个虚拟DOM
    3.对比两个虚拟DOM,找不同(DOM diff),然后局部更新DOM

4.复杂 state

  • 类组件里有n和m
    1.setState的时候可以只set n,不用写m,因为类组件的setState会自动合并第一层属性
    2.当修改 user.name 的时候,属于第二层,setState不会合并第二层属性
    ——解决:使用...操作符
this.state = {
  n:0,
  m:0,
  user:{
    name:"frank",
    age:18
  }
}
this.setState({n:this.state.n+1})
this.setState({...this.state.user,name:"jack"})
  • 函数组件里有n和m
    1.推荐m和n分开写
    2.因为当m和n写在一起时,set其中一个值(如m),React不会自动合并以前的属性,如果不写就会把n设置为undefined
    3.用...state把之前的数据拷贝过来(推荐分开写)
const [n,setN] = React.useState(0)
const [m,setM] = React.useState(0)
正常setN和setM
//等价于
const [state,setState] = React.useState({n:0,m:0})
setState({...state,m:state.m+1})
  • 总结
    1.类组件的setState会自动合并第一层属性
    2.但不会合并第二层属性,需要使用Object.assign或者...操作符
    3.函数组件的setX则完全不会合并
    4.要合并只能用...操作符

5.函数组件和类组件的事件绑定

  • 类组件的事件绑定
    1.第一种方法是最好的,因为第二种会让 add 函数里的 this 变成window
    2.由于this.addN 一定会去调用 this.setState
    3.当用户点击button的时候,React会调用 button.onClick.call(null,event)
    ——因此在onClick函数中,this就是null,window自动补位
    ——因此addN里面的this会变成window
    ——而箭头函数没办法改变this,addN的this就还是当前实例
//写法一
<button onClick={ ()=>this.addN() }>n+1</button>
//写法二
<button onClick={ this.addN() }>n+1</button>
  • 还是觉得在标签里写箭头函数太长
    1.则令一个变量 this._addN = ()=>this.addN() 将其替换掉
    2.而addN函数声明后只使用了一次,整合起来
  • 最终的事件绑定写法
    1.组委会约定声明:事件名=箭头函数
    ——写在state外面,且省掉声明的this
    2.使用:this.函数事件名
//事件名赋值,写在state外面
addN = ()=> this.setState({n: this.state.n + 1})
//绑定事件
<button onClick={ this.addN }>n+1</button>

6.React 和Vue

  • 相同点
    1.都是对视图的封装,React是用类和函数表示一个组件,而Vue是通过构造选项构造一个组件
    2.都提供了createElement的XML缩写,React提供的是JSX语法,而Vue提供的是模板写法template
  • 不同点
    React是把HTML放在JS里面写(HTML in JS),而Vue是把JS放在HTML里面写(JS in HTML)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值