React高级(生命周期)

1.PropTypes校验传递值

在父组件向子组件传递数据时,使用了属性的方式,也就是props。但是在实际开发中,需要对这些传递过去的值进行校验,包括非空,格式的验证。
我们在Xiaojiejie.js组件里传递了4个值,有字符串,有数字,有方法,这些都是可以使用PropTypes限制的。在使用需要先引入PropTypes:

import PropTypes from 'prop-types'

引入后,就可以在组件的下方进行引用了,需要注意的是代码要写在子组件的最下面(不是类里边):

class XiaojiejieItem extends Component {
    
    
	...
}
//进行数据的校验
XiaojiejieItem.propTypes= {
    
    
    avname:PropTypes.string.isRequired,   //isRequired表示该属性必须传值
    content:PropTypes.string, //内容必须为字符串类型
    index:PropTypes.number, //索引必须是数字类型
    deleteItem:PropTypes.func //删除元素必须是一个方法
}

必传值的校验
又例如现在格式改为:

render() {
    
     
    return ( 
        <div onClick={
    
    this.handleClick}>
            {
    
    this.props.name}为你做- {
    
    this.props.content}
        </div>
    );
}

加了一个{this.props.name},但是这个值传不传其实无所谓,不传的话也不会报错。该如何去规定这个值是必传的呢?需要使用isRequired关键字了,它表示必须进行传递,如果不传递就报错。在校验代码中加入下面这条语句:

name:PropTypes.string.isRequired

使用默认值defaultProps
defalutProps就可以实现默认值的功能,比如现在把name的默认值设置成"小明" ,然后把name的属性删除掉:

XiaojiejieItem.defaultProps= {
    
            //defaultProps表示属性的默认值
    name:'小明'
}

2.ref的使用方法

例如下面这段代码:

inputChange(e){
    
    
    this.setState({
    
    
        inputValue:e.target.value
    })
}

e.target.value显得不够语义化,这个时候就可以使用ref来改写。如果要使用ref来进行,需要现在JSX中进行绑定, 绑定时最好使用ES6语法中的箭头函数,这样可以简洁明了绑定的DOM元素:

<input 
    id="jspang" 
    className="input" 
    value={
    
    this.state.inputValue} 
    onChange={
    
    this.inputChange.bind(this)}
    ref={
    
    (input)=>{
    
    this.input=input}}
/>

绑定完了之后就可以写为:

inputChange(){
    
    
    this.setState({
    
    
        inputValue:this.input.value //这里的this.input指的就是文本框
    })
}

ref的坑
比如现在我们要用ref绑定取得要服务的数量,可以先用ref进行绑定:

<ul ref={
    
    (ul)=>{
    
    this.ul=ul}}>
    {
    
    
        this.state.list.map((item,index)=>{
    
    
            return (
                <XiaojiejieItem 
                key={
    
    index+item}  
                content={
    
    item}
                index={
    
    index}
                deleteItem={
    
    this.deleteItem.bind(this)}
                />
            )
        })
    }
</ul>  

绑定后可以在addList()方法中,获取当前有几个<div>(有几行数据)的值.

addList(){
    
    
    this.setState({
    
    
        list:[...this.state.list,this.state.inputValue],
        inputValue:''
    })
    console.log(this.ul.querySelectorAll('div').length)
}

经过测试发现能输出但是数量不正确,(就是这个坑),其实这个坑是因为React中更多setState是一个异步函数所造成的。也就是这个setState,代码执行是有一个时间的,简单的说,就是因为是异步,还没等虚拟Dom渲染,我们的console.log就已经执行了。

改进方法就是将语句放在setState的回调函数中,如下所示:

addList(){
    
    
    this.setState({
    
    
        list:[...this.state.list,this.state.inputValue],
        inputValue:''
    },()=>{
    
    
        console.log(this.ul.querySelectorAll('div').length)
    })
}

3.React生命周期

React生命周期
React生命周期的四个大阶段:

  • Initialization: 初始化阶段。
  • Mounting: 挂载阶段。
  • Updation: 更新阶段。
  • Unmounting: 销毁阶段。

生命周期函数就是在某一个时刻组件自动调用执行的函数。就好比人的一生一定会有出生,成人,衰老,死亡这几个阶段,它们是无法避免的,到了一定的年龄就自然会经历。
之前写的Xiaojiejie.js里边的render()函数,就是一个生命周期函数,它在state发生改变时自动执行。这就是一个标准的自动执行函数。但是constructor我们叫构造函数,它是ES6的基本语法。虽然它和生命周期函数的性质一样,但不能认为是生命周期函数。但是可以把它当成一个生命周期函数,把它看成React的Initialization阶段,定义属性(props)和状态数据(state)。
1.Initialization:初始化阶段。
2.Mounting挂载阶段
Mounting阶段叫挂载阶段,伴随着整个虚拟DOM的生成,它里边有三个小的生命周期函数,分别是:

  • componentWillMount: 在组件即将被挂载到页面的时刻执行。
  • render: 页面stateprops发生变化时执行。
  • componentDidMount: 组件挂载完成时被执行。

componentWillMount

componentWillMount(){
    
    
    console.log('componentWillMount----组件将要挂载到页面的时刻')
}

componentDidMount

componentDidMount(){
    
    
    console.log('componentDidMount----组件挂载完成的时刻执行')
}

render

render(){
    
    
    console.log('render---组件挂载中.......')
}

componentWillMountcomponentDidMount这两个生命周期函数,只在页面刷新时执行一次,而render函数是只要有stateprops变化就会执行。

3.Updation更新阶段。
shouldComponentUpdate:
shouldComponentUpdate函数会在组件更新之前,自动被执行。它要求返回一个布尔类型的结果必须有返回值,这里就直接返回一个true了(真实开发中,这个是有大作用的)。

shouldComponentUpdate(){
    
    
    console.log('shouldComponentUpdate---组件发生改变前执行')
    return true
}

返回结果是每次文本框发生改变时都会随着改变。如果你返回了false,这组件就不会进行更新了。 简单点说,就是返回true,就同意组件更新;返回false,就反对组件更新
componentWillUpdate:
componentWillUpdate组件更新之前,但shouldComponenUpdate之后被执行。但是如果shouldComponentUpdate返回false,这个函数就不会被执行了

//shouldComponentUpdate返回true才会被执行。
componentWillUpdate(){
    
    
    console.log('componentWillUpdate---组件更新前,shouldComponentUpdate函数之后执行')
}

componentDidUpdate:
componentDidUpdate组件更新之后执行,它是组件更新的最后一个环节

componentDidUpdate(){
    
    
    console.log('componentDidUpdate----组件更新之后执行')
}

componentWillReceiveProps:
子组件接收到父组件传递过来的参数,父组件render函数重新被执行,这个生命周期就会被执行。凡是组件都有生命周期函数,所以子组件也是有的,并且子组件接收了props,这时候函数就可以被执行了。要注意:

  • 这个组件第一次存在于Dom中,函数是不会被执行的;
  • 如果已经存在于Dom中,函数才会被执行。

4.Unmounting销毁阶段
componentWillUnmount:
XiaojiejieItem.js,写入:

//当组件从页面中删除的时候执行
componentWillUnmount(){
    
    
    console.log('child - componentWillUnmount')
}

当点击一行数据删除时就会执行这个函数。
接下去就是用React生命周期函数来对程序代码进行性能优化:

代码中有一个地方存在性能消耗,那就是在文本框输入的时候,每输入一个字母或者汉字,文本框会重新渲染,下面的列表数据也会渲染但其实下面的根本不需要渲染,只需要点击增加服务按钮时重新渲染即可。

如果你看不出来,在XiaojiejieItem.jsrender函数改写成:

render() {
    
     
    console.log('child-render')
    return ( 
        <div onClick={
    
    this.handleClick}>
            {
    
    this.props.avname}为你做- {
    
    this.props.content}
        </div>
    );
}

你会发现在你输入内容的时候,控制台会频繁地输出child-render,但是列表数据并没有变化。

改进方法就是:
直接在XiaojiejieItem.js中加入下面的代码:

shouldComponentUpdate(){
    
    
    return false;
}

意思就是不允许子组件进行更新渲染。这时候在浏览器中查看,问题已经没有了。但是这样做太暴力了,直接否定了所有的东西,那如果在真实项目中,需要改变值属性值,达到渲染就没办法了。所以这种写法不恰当。

shouldComponentUpdate有两个参数:
nextProps:变化后的属性;
nextState:变化后的状态;

shouldComponentUpdate(nextProps,nextState){
    
    
    if(nextProps.content !== this.props.content){
    
     当子组件内容发生变化时才重新进行渲染
        return true
    }else{
    
    
        return false
    }
}

4.Axios

1.React用Axios请求远程数据

ajax可以远程请求,但是这写起来太麻烦了,我们用程序的ajax请求框架Axios来实现。首先安装Axios

npm install -save axios

关于npm下载的几个知识点:

  • npm install xxx: 安装项目到项目目录下,不会将模块依赖写入devDependenciesdependencies

  • npm install -g xxx: -g的意思是将模块安装到全局,具体安装到磁盘哪个位置,要看 npm cinfig prefix的位置

  • npm install -save xxx-save的意思是将模块安装到项目目录下,并在package文件的dependencies节点写入依赖。

  • npm install -save-dev xxx-save-dev的意思是将模块安装到项目目录下,并在package文件的devDependencies节点写入依赖。

安装好axiso之后,需要在使用ajax的地方先引入axios,比如现在想在Xiaojiejie.js中使用axios,写入下面的代码进行引入:

import axios from 'axios'

引入后,可以在componentDidMount生命周期函数里请求ajax,我也建议在componentDidMount函数里执行,因为在render里执行,会出现很多问题,比如一直循环渲染;在componentWillMount里执行,在使用React Native时,又会有冲突。所以强烈建议在componentDidMount函数里作ajax请求。

componentDidMount(){
    
    
    axios.post('https://web-api.juejin.im/v3/web/wbbr/bgeda')
        .then((res)=>{
    
    console.log('axios 获取数据成功:'+JSON.stringify(res))  })
        .catch((error)=>{
    
    console.log('axios 获取数据失败'+error)})
}

2.Axios请求EasyMock数据

选择使用Easy-mock来模拟接口数据。
EasyMock网站:EasyMock

{
    
    
  "data": ['基础按摩', '躺式采耳', '中药泡脚']
}

接着:

componentDidMount(){
    
    
    axios.get('xxxx')
        .then((res)=>{
    
    
            console.log('axios 获取数据成功:'+JSON.stringify(res))

            this.setState({
    
    
                list:res.data.data
            })
          })
        .catch((error)=>{
    
    console.log('axios 获取数据失败'+error)})
}

5.CSS3实现React动画

CSS3React中制作一个显示隐藏的动画特效,注意这是用CSS3实现的,其实React只做了业务逻辑。
首先在src文件夹下,新建一个Boss.js文件。然后用快速生成的方式生成基本结构:

import React, {
    
     Component } from 'react';
class Boss extends Component {
    
    
    constructor(props) {
    
    
        super(props);
        this.state = {
    
      }
    }
    render() {
    
     
		return ( 
           <div>
               <div>BOSS级人物-孙悟空</div>
               <div><button>召唤Boss</button></div>
           </div>
         );
    }
}

export default Boss;

界面UI设计好之后开始编写业务逻辑
先在constructor里增加stateisShow

this.state = {
    
     
    isShow:true
}

接着将页面上的元素进行数据绑定:

<div className={
    
    this.state.isShow ? 'show' : 'hide'}>BOSS级人物-孙悟空</div>

需要点击按钮时,有响应的事件,所以需要一个方法,我们编写一个toToggole()方法:

toToggole(){
    
    
    this.setState({
    
    
        isShow:this.state.isShow ? false : true
    })
}

最后给按钮上绑定点击事件:

<div><button onClick={
    
    this.toToggole}>召唤Boss</button></div>

注意这里需要到constructor里绑定一下this

constructor(props) {
    
    
    super(props);
    this.state = {
    
     
        isShow:true
    }
    this.toToggole = this.toToggole.bind(this);
}

还可以加入动画效果:
style.css

.show{
    
     opacity: 1; transition:all 1.5s ease-in;}
.hide{
    
    opacity: 0; transition:all 1.5s ease-in;}

猜你喜欢

转载自blog.csdn.net/Aurora_1970s/article/details/107358575