只有页面在第一次渲染的时候才会执行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(
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
知识点:
{/* */}
{/* 注意在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;
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)