React中级

React中级,第1张

React 旧生命周期 Initialization 初始化阶段(Initialization): 没有生命周期函数,只是在constructor里做数据的设置 Mounting

只有页面在第一次渲染的时候才会执行Mounting过程

UNSAFE_componentWillMount组件挂载前

有this 没dom 可以不通过setState来修改数据

因为这个生命周期在render函数之前,所以就不用通过setState修改数据

可以做网路请求 能不用就不用都快被干掉了

render函数:挂载

注意父组件的render执行 子组件的render 必定执行

componentDidMount函数:挂载完毕

有this 有dom 可以修改数据 通过setState

dom的初始化 *** 作 网络请求

子组件的优先挂载完成 之后才是父组件

Updation(更新): 数据发生变化时执行

里面分别有两个一个是props更新的时候触发

一个是自己states更新的时候触发

props更新的时候 UNSAFE_componentWillReceiveProps

可以在子组件的render函数执行前获取新的props,从而更新子组件自己的state。
这样的好处是,可以将数据请求放在这里进行执行,需要传的参数则从componentWillReceiveProps(nextProps)中获取。而不必将所有的请求都放在父组件中。于是该请求只会在该组件渲染时才会发出,从而减轻请求负担。

实现监听props改变 重新发起请求 修改state值,不需要setState,因为后面有render函数

里面第一个参数是改变后的props

这个生命周期要注意:数据改变的来源尽量只来自于1方 ,例如当通过props修改子组件的state.age,有通过子组件自身修改state.age会相互覆盖的

UNSAFE_componentWillReceiveProps(props) {
    // 实现监听props改变 重新发起请求 修改state值
    console.log("props数据发生改变");
    console.log(props);
    // this.state.name = props.name;
    // 修改数据不需要执行state
    // 注意数据改变的来源尽量只来自于1方
  }
shouldComponentUpdate

性能优化的声明周期 可以控制结接下来的render是否执行 默认是ture

参数是修改后的prop 和 state

shouldComponentUpdate(props, state) {
     return state.name !== this.state.name;
  }  //这样的话只有在state.name改变的时候才会渲染
//但是有个问题,当监听多个state值是否更新怎么写

当监听多个state值是否更新怎么写  (不推荐JSON.stringify存在效率问题)

shouldComponentUpdate(props, state) {
    return JSON.stringify(this.state) !== JSON.stringify(state);
  }  //不推荐JSON.stringify存在效率问题

PureComponent 组件 自带shouldComponentUpdate

在用的时候

import React, { PureComponent} from "react";
class App extends PureComponent{
}
componentWillUpdate() 接下来是组件更新前

this有 数据应该是新的 dom是老的  不能做数据修改的 *** 作

UNSAFE_componentWillUpdate() {
    console.log("父组件更新前");
    console.log(this.state.age);//会变
    console.log(this.ageRef.current.innerHTML)//不会变
  }
再执行render渲染函数 componentDidUpdate()组件更新结束

不能做修改数据的 *** 作 死循环 -> 可以通过shouldComponentUpdate 挽救一下

componentDidUpdate() {
    console.log("父组件更新结束");
     console.log(this.state.age) //改了
     console.log(this.ageRef.current.innerHTML)//改了
  
  }

state与props一样,就是少了 UNSAFE_componentWillReceiveProps

componentWillUnmount 组件卸载

指在某个组件不在显示的时候触发。就很vue里面的v-if=false的时候触发

新的生命周期

 static getDerivedStateFromProps

这个生命周期函数是为了替代componentWillReceiveProps存在的,所以在你需要使用componentWillReceiveProps的时候,就可以考虑使用getDerivedStateFromProps来进行替代了然后就进行render进行

 static getDerivedStateFromProps(nextProps, nextState)两个参数,第一个参数是传过来的props,第二参数是现在里面的属性

class Son1 extends Component {
  constructor() {
    super();
  }
  state = {
    age:2,
    name:'li'
  }
  static getDerivedStateFromProps(nextProps, nextState) {
    console.log("getDerivedStateFromProps")
    console.log(this)
    console.log(nextProps,nextState)
    // 静态方法不能获取this
    // 参数是新的props,state
    // 需要return 数据放入到state 将props 映射到state里
    // 需要根据不同的情况去return 不同值
    // 将props来源的数据映射到state
    const  propsName  = nextProps.name
    const  stateName = nextState.name 
    if(stateName) {  //这个判断是子组件的state要是有name就不能通过props传递过来的值进行改变
      return null
    } else {
      
      return { name: propsName }
    }
  }
componentDidMount()  组件挂载后 getSnapshotBeforeUpdate()组件更新前快照 

三个参数:

prevProps 组件更新前的props,   prevState,组件更新前的State      shap?

更新之前记录数据,返回给componentDidUpdate

必须和componentDidUpdate成对出现

 componentDidUpdate(props,state,shap) 更新结束

三个参数,分别是getSnapshotBeforeUpdate传递过来的更新前的快照

用法:

 getSnapshotBeforeUpdate(prevProps,prevState, shap) {
    console.log("组件更新前快照") 
    console.log(prevProps,prevState,shap)
    // 更新之前记录数据,返回给componentDidUpdate
    // 必须和componentDidUpdate成对出现
    return {
      name:123
    }
  }
  componentDidUpdate(props,state,shap) {
    // 接受getSnapshotBeforeUpdate 保存的快照信息
    console.log("更新结束")
    console.log(props,state,shap)
  }
}
context上下文

通过context进行通信

1. 创建context对象

2. 对上线文对象处理,目的是提供者和消费者配对

3. 通过provider value 属性提供数据

4. 通过consumer消费者获取数据

5. context上下文的数据直接修改无效,在传递value的同时传递一个修改上下文的方法

用法1

首先创建一个nameContext.js文件夹里面是用来引入createContext,创建文件夹是为了区分多个上下文的

import { createContext } from "react";
const NameContext = createContext();
const { Consumer, Provider } = NameContext;
export default NameContext;
export { Consumer, Provider };

在孙子组件里面Grandson2.js   <>包裹因为在render  consumer的时候外层会包裹一层div

import React, { PureComponent, createContext } from "react";
import { Consumer } from "./nameContext"
import ColorContext from "./colorContext";
class GrandSon2 extends PureComponent { 
  constructor() {
    super();
  }
  state = {}
  render() {
    console.log(this) 
    return (
      <>
      {/* 第一个上下文 */}
        //通过组件来呈现视图
        {
          (context) => //content是该组件的上下文,里面有index爷爷组件传递过来的name,与changeName参数,就可以直接使用了
            return (
              
                孙子组件2
                {context.name}
                
               
            )
          }
        }
      
      {/* color上下文 */}
    
      
    )
  }

  componentDidMount() {
    console.log("grandson2", this)

  }
}

/*
1. consumer 内部是可以获取上下文的
2. consumer 内部有一个渲染函数 
this.props.chilren()
3. 将上下文作为渲染函数的参数
4. 渲染函数指的就是Consumer 组件标签中间的函数
*/ 

export default GrandSon2;

在son2.js里面

import React, { PureComponent } from "react";
import GrandSon2 from "./GrandSon2";
class Son2 extends PureComponent {
  constructor() {
    super();
  }
  state = {}
  render() {
    return (
    
      子组件2
      
       
      
    );
  }


}

export default Son2;

在爷爷组件里面

import React, { PureComponent } from "react";
import ColorContext from "./colorContext";
import { Provider } from "./nameContext";
import Son1 from "./Son1";
import Son2 from "./Son2";
class Demo extends PureComponent {
  constructor() {
    super();
  }
  state = {
    name: "韩梅梅",
  };

  changeName = (name) => {
    this.setState({ name });
  };
  render() {
    const { name } = this.state;
    const { changeName } = this;
    return (
      { name,changeName }}>//通过Provider把name,与changeName 属性传给孙子,孙子接收到就可以使用了
       
          
            contextDemo
            
            
          
       
      
    );
  }

}

export default Demo;
方法2 通过静态方法static

  static contextType = NameContext; //通过这个方法可以直接拿到context,不用Consumer

还是使用刚开始定义的nameContext.js

然后是son1父组件son1.js  与son2.js是一样的不一样的是在接收content的那个组件

son1.js

import React, { PureComponent } from "react";
import ColorContext from "./colorContext";
import NameContext from "./nameContext";
import GrandSon1 from "./GrandSon1";
class Son1 extends PureComponent {
  static contextType = NameContext;
  // 静态属性只能赋值一个上下文 多个还是需要通过consumer实现
  constructor() {
    super();
  }
  state = {}
  render() {
    return (
    
      子组件1
      
    );
  }
  componentDidMount() {
    console.log("son1",this)
  }
}

export default Son1;

Grandson1.js 通过静态方法拿到contxt

import React, { PureComponent } from "react";
import ColorContext from "./colorContext";
import NameContext from "./nameContext";
import GrandSon1 from "./GrandSon1";
class Son1 extends PureComponent {
  static contextType = NameContext; //通过这个方法可以直接拿到context,不用Consumer
  constructor() {
    super();
  }
  state = {}
  render() {
    return (
    
      子组件1
      
    );
  }
  componentDidMount() {
    console.log("son1",this)
  }
}

export default Son1;
如果有多个上下文

注意这里我们只能用第一种方法通过consumer实现,不能通过静态方法static实现

实现方法:

我们在创建一个colorContext.js

import { createContext } from "react"
const  ColorContext = createContext()
export default ColorContext 

在son2里

import React, { PureComponent } from "react";
import GrandSon2 from "./GrandSon2";
class Son2 extends PureComponent {
  constructor() {
    super();
  }
  state = {}
  render() {
    return (
    
      子组件2
      
       
      
    );
  }


}

export default Son2;

在Grandson2.js里面 ,通过来区分是哪一个上线文

import React, { PureComponent, createContext } from "react";
import { Consumer } from "./nameContext"
import ColorContext from "./colorContext";
class GrandSon2 extends PureComponent { 
  constructor() {
    super();
  }
  state = {}

  render() {
    console.log(this)
    return (
      <>
      {/* 第一个上下文 */}
      
        {
          (context) => {
            console.log("nameContext",context)
            return (
              
                孙子组件2
                {context.name}
                
               
            )
          }
        }
      
      {/* color上下文 */} 
       
        {(context) => {
          console.log("ColorContext.Consumer",context)
          return {context.color}
        }}
      
      
    )
  }

  componentDidMount() {
    console.log("grandson2", this)

  }
}

export default GrandSon2;

在index.js爷爷组件里面

import React, { PureComponent } from "react";
import ColorContext from "./colorContext";
import { Provider } from "./nameContext";
console.log(ColorContext);
// console.log("context", context)
import Son1 from "./Son1";
import Son2 from "./Son2";
class Demo extends PureComponent {
  constructor() {
    super();
  }
  state = {
    name: "韩梅梅",
  };

  changeName = (name) => {
    this.setState({ name });
  };
  render() {
    const { name } = this.state;
    const { changeName } = this;
    return (
      { name ,changeName}}> //通过Provider 包裹的形式,谁包裹谁无所谓
        { color: 'red' }}>
          
            contextDemo
            
            
          
        
      
    );
  }

  componentDidMount() {}
}

export default Demo;
portal

首先来判断一句话的真假,所有组件都是挂载在根组件上,这句话没错,但是说所有组件的dom都是挂载到根组件的dom上,这就话就错了,我们可以通过portal这个属性来修改组件挂载的位置,例如做个

 这样的样式,我们可以是根组件的孙子组件,但是我们可以把dom挂载在与根组件同级的效果上,这样显示的时候我们就不用z-index:99999了,但是组件的先后顺序并没变,所以我们点击这个图的任意位置,依然会冒泡到他的爷爷组件

接下来我们看下这个怎么用

首先先创建一个Model.js 是用来实现遮罩层这个组件的

知识点:

要引入import ReactDOM from "react-dom";

要创建两个类最后一个类用第一个类return ReactDOM.createPortal(,document.body) 后面的document.body就是挂载到哪里

import React, { PureComponent } from "react";
import ReactDOM from "react-dom";
class Modal extends PureComponent {
  constructor() {
    super();
  }
  state = {};
  render() {
    return (
      {
          position: "fixed",
          top: 0,
          left: 0,
          right: 0,
          bottom: 0,
          background: "rgba(0,0,0,.6)",
          display: "flex",
          justifyContent: "center",
          alignItems: "center",
        }}
      >
        loading
        
      
    );
  }
  componentDidMount() {}
}
class Box extends PureComponent {
  render() {
    return ReactDOM.createPortal(,document.body)
  }
}

export default Box;

在index.js里面

    import React, { PureComponent } from "react";
import Modal from "./Modal";
class Demo extends PureComponent {
  constructor() {
    super();
  }
  state = {
    show: false,
  };
  close = () => {
    this.setState({ show: false });
  };

  render() {
    return (
      
        portal
        
         {
            this.close();
          }}
        >
          {this.state.show && }
        
      
    );
  }

  componentDidMount() {}
}

export default Demo;
高阶组件

hoc 就是一个函数

接受一个组件作为参数

返回一个新的组件

在返回的新组件中渲染参数组件

将多个组件中的通用能力进行抽离,抽离为组件进行逻辑处理

处理结束将结果通过props 传递给抽离前的组件

hoc特点 参数都是从props中获取的

例如:在son1里面有一部分逻辑与son2的逻辑一模一样,我们就可以把这一部分的逻辑放入到高阶组件里面,然后导出这个组件的时候就把这个组件传到高阶组件里面,导出去,在父组件里面使用

例子:在index组件state里面有个name,把这个name存到localstorng里面然后son1组件拿到这个localstorng的name,赋值给son1组件里面的props.name,同样son2也是这样的 *** 作,所以我们可以把son1与son2组件里面拿到这个localstorng的name,赋值给son1,son2组件里面的props.name,这个逻辑可以写到高阶组件里面

代码展示:

首先是hoc.js

知识点:  因为会多一层div,所以用Fragment来代替

 
        
       {/*   */}
{/* 注意在props传值得时候可以直接传递一个对象不用是一个自定义属性={}
 result是{name: '韩梅梅', age: 123}*/}
      );
import React, { Component, Fragment } from "react";
export default (ParamComponent) => {//这个地方的ParamComponent就是传递进来的组件
  
  class NewComponent extends Component {
    constructor() {
      super();
    }
    state = {
      name: ''
    }
    render() {
      return (
       //因为会多一层div,所以用Fragment来代替
        
//这里通过自定义属性传到组件的props里面
      );
     
    }
    componentDidMount() { //这个地方就是son1,son2 里面公共有的方法
      let name = localStorage.getItem("name");
      this.setState({name})
    }
  }
  return NewComponent;
}

son1.js

import React, { PureComponent } from "react";
import hoc from "./hoc";
class Hello extends PureComponent {
  constructor(props) {
    super(props);
  }
  state = {
    name: '',
  }

  render() {
    return (
    
     sayhello:{ this.props.name}
    );
  }
  // componentDidMount() {  //这里是之前son1,与son2共有的逻辑,所以就不写在组件内部,都写在高阶组件hoc里面了
  //   let name = localStorage.getItem("name");
  //   this.setState({name})
  // }
}
export default hoc(Hello);//把Hello这个组件当作参数放到hoc高阶函数里面返回一个新的组件

son2.js  

知识点:可用修饰器

import React, { PureComponent } from "react";
import Hoc from "./hoc";
@Hoc //这个地方用到了装饰器,就相当于把Byby放到Hoc 的参数里面
class Byby extends PureComponent {
  constructor() {
    super();
  }
  state = {
    name: '',
  }

  render() {
    console.log("byby",this)
    return (
    
     sayByBy:{ this.props.name}
    );
  }
  // componentDidMount() {
  //   let name = localStorage.getItem("name");
  //   this.setState({name})
  // }
}
export default Byby

在父组件进行挂载的时候,就是之前正常的挂载,变的只是son1,son2组件,并且多了个Hot高阶组件

index.js

import React, { PureComponent } from "react";
import Hello from "./hello";
import Byby from "./byby";
class Demo extends PureComponent {
  constructor() {
    super();
  }
  state = {}

  render() {
    return (
    
      高阶组件hoc
      
      
    );
  }

  componentDidMount() {
    localStorage.setItem("name","韩梅梅")
  }
}
export default Demo;

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1320315.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-11
下一篇 2022-06-11

发表评论

登录后才能评论

评论列表(0条)

保存