React相关扩展二(Fragment、Content、useContext、组件优化、render props、错误边界)(十)

news2025/1/16 16:13:08

系列文章目录

第一章:React基础知识(React基本使用、JSX语法、React模块化与组件化)(一)
第二章:React基础知识(组件实例三大核心属性state、props、refs)(二)
第三章:React基础知识(事件处理、受控组件与非受控组件、高阶函数、组件的生命周期)(三)
第四章:React脚手架应用(创建脚手架、代理配置、ajax相关、组件通信)(四)
第五章:react-router5路由相关一(路由相关概念、基本使用、NavLink与NavLink的封装、Switch的使用、严格匹配、路由重定向、路由组件与一般组件的区别)(五)
第六章:react-router5路由相关二(嵌套路由、路由传参、replace、编程式路由导航、withRouter的使用、BrowserRouter与HashRouter的区别)(六)
第七章:React-Router6路由相关一(路由的基本使用、重定向、NavLink·、路由表、嵌套路由)(七)
第八章:React-Router6路由相关二(路由传参、编程式路由导航、路由相关hooks)(八)
第九章:React相关扩展一(setState、lazyLoad、Hooks相关)(九)
第十章:React相关扩展二(Fragment、Content、组件优化、render props、错误边界)(十)


文章目录

  • 系列文章目录
    • 一、 Fragment
    • 二、Context
      • 2.1 使用
    • 三、useContext
    • 四、 组件优化
      • 4.1 Component的2个问题
      • 4.2 效率高的做法
      • 4.3 原因
      • 4.4 解决
    • 五、render props
      • 5.1 如何向组件内部动态传入带内容的结构(标签)?
      • 5.2 children props
      • 5.3 render props
    • 六、错误边界
      • 6.1 理解:
      • 6.2 特点:


一、 Fragment

(1) 作用

可以不用必须有一个真实的DOM根标签了可以将内部内容当做一个整体,而不产生其他标签,项目运行后会自动删除Fragment标签

(2) 使用

<Fragment><Fragment>
<></>

代码案例:
Demo.jsx

import React, { Component,Fragment } from 'react'

export default class Demo extends Component {
	render() {
		return (
			<Fragment key={1}>
				<input type="text"/>
				<input type="text"/>
			</Fragment>
		)
	}
}

App.js

import React, { Component, Fragment } from 'react'
import Demo from './components/3_hooks'

export default class App extends Component {
	render () {
		return (
			<>
				<Demo />
			</>
		)
	}
}


二、Context

一种组件间通信方式, 常用于【祖组件】与【后代组件】间通信

2.1 使用

1) 创建Context容器对象:

	const XxxContext = React.createContext()  

2) 渲染子组时,外面包裹xxxContext.Provider, 通过value属性给后代组件传递数据:

	<xxxContext.Provider value={数据}>
		子组件
    </xxxContext.Provider>

3) 后代组件读取数据:

	//第一种方式:仅适用于类组件 
	  static contextType = xxxContext  // 声明接收context
	  this.context // 读取context中的value数据
	  
	//第二种方式: 函数组件与类组件都可以
	  <xxxContext.Consumer>
	    {
	      value => ( // value就是context中的value数据
	        要显示的内容
	      )
	    }
	  </xxxContext.Consumer>

注意: 在应用开发中一般不用context, 一般都它的封装react插件

代码案例:

import React, { Component } from 'react'
import './index.css'
import './B.tsx'

//创建Context对象
export const MyContext = React.createContext()
const {Provider,Consumer} = MyContext

//A.tsx
export default class A extends Component {

	state = {username:'tom',age:18}

	render() {
		const {username,age} = this.state
		return (
			<div className="parent">
				<h3>我是A组件</h3>
				<h4>我的用户名是:{username}</h4>
				<Provider value={{username,age}}>
					<B/>
				</Provider>
			</div>
		)
	}
}
//B.tsx
import React, { Component } from 'react'
import './index.css'

export default class B extends Component {
	render() {
		return (
			<div className="child">
				<h3>我是B组件</h3>
				<C/>
			</div>
		)
	}
}

//c.tsx
import React, { Component } from 'react'
import './index.css'

//创建Context对象
import { MyContext } from './A'
const {Consumer} = MyContext

/*export default class C extends Component {
	//声明接收context
	static contextType = MyContext
	render() {
		const {username,age} = this.context
		return (
			<div className="grand">
				<h3>我是C组件</h3>
				<h4>我从A组件接收到的用户名:{username},年龄是{age}</h4>
			</div>
		)
	}
} */

export default function C(){
	return (
		<div className="grand">
			<h3>我是C组件</h3>
			<h4>我从A组件接收到的用户名:
			<Consumer>
				{value => `${value.username},年龄是${value.age}`}
			</Consumer>
			</h4>
		</div>
	)
}

运行结果:

在这里插入图片描述


三、useContext

与 Context 一样,在 React Hooks 中也提供了更加高级的一种组件中传递值的方式,不再需要一层一层的向下传递,而是可以隔层传递。
1) 创建Context容器对象:

  export const XxxContext = React.createContext()  

2) 渲染子组时,外面包裹xxxContext.Provider, 通过value属性给后代组件传递数据:

	<xxxContext.Provider value={数据}>
		子组件
    </xxxContext.Provider>

3) 后代组件读取数据:

import {xxxContext } from "./XXX";
	  
const { x } = useContext(xxxContext);
render(){
  return (
    <div>
      	{x}
    </div>
  );
}

代码案例片段:

A.jsx

import React, { Component } from "react";
import "./index.css";
import B from "./B";
//创建Context对象
export const MyContext = React.createContext();
const { Provider } = MyContext;

export default class A extends Component {
  state = { username: "tom", age: 18 };

  render() {
    const { username, age } = this.state;
    return (
      <div className="parent">
        <h3>我是A组件</h3>
        <h4>我的用户名是:{username}</h4>
        <Provider value={{ username, age }}>
          <B />
        </Provider>
      </div>
    );
  }
}

B.jsx

import React from "react";
import "./index.css";
import C from "./C";

const B = () => {
  return (
    <div className="child">
      <h3>我是B组件</h3>
      <C />
    </div>
  );
};

export default B;

C.jsx

import React, { useContext } from "react";
import "./index.css";
import { MyContext } from "./A";

const C = () => {
  const { username, age } = useContext(MyContext);
  return (
    <div className="grand">
      <h3>我是C组件</h3>
      <h4>
        我从A组件接收到的用户名:
        {username},年龄是{age}
      </h4>
    </div>
  );
};

export default C;

运行结果:

在这里插入图片描述

四、 组件优化

4.1 Component的2个问题

  1. 只要执行setState(),即使不改变状态数据, 组件也会重新render()

  2. 只当前组件重新render(), 就会自动重新render子组件 ==> 效率低

4.2 效率高的做法

只有当组件的state或props数据发生改变时才重新render()

4.3 原因

Component中的shouldComponentUpdate()总是返回true

4.4 解决

  • 办法1:

    • 重写shouldComponentUpdate()方法

    • 比较新旧state或props数据, 如果有变化才返回true, 如果没有返回false

    代码案例片段:

    import React, { Component } from "react";
    import "./index.css";
    
    export default class Parent extends Component {
      state = { carName: "奔驰c36", stus: ["小张", "小李", "小王"] };
    
      addStu = () => {
        /* const {stus} = this.state
    		stus.unshift('小刘')//不要直接修改state数据, 而是要产生新数据,无法触发页面渲染
    		this.setState({stus})
    	 */
    
        const { stus } = this.state;
        this.setState({ stus: ["小刘", ...stus] });
      };
    
      changeCar = () => {
        this.setState({ carName: "迈巴赫" });
    
        // const obj = this.state;
        // obj.carName = "迈巴赫";//不要直接修改state数据, 而是要产生新数据,无法触发页面渲染
        // console.log(obj === this.state);//true
        // this.setState(obj);
      };
    
      shouldComponentUpdate(nextProps, nextState) {
        console.log(this.props, this.state); //目前的props和state
        console.log(nextProps, nextState); //接下要变化的目标props,目标state
        return this.state.carName !== nextState.carName; //如果车名没有发生改变,则返回false,阻止渲染,这样虽然添加了一个小李,但是页面也不会渲染
      }
    
      render() {
        console.log("Parent---render");
        const { carName } = this.state;
        return (
          <div className="parent">
            <h3>我是Parent组件</h3>
            {this.state.stus}&nbsp;
            <span>我的车名字是:{carName}</span>
            <br />
            <button onClick={this.changeCar}>点我换车</button>
            <button onClick={this.addStu}>添加一个小刘</button>
            <Child carName={carName} />
          </div>
        );
      }
    }
    
    class Child extends Component {
      shouldComponentUpdate(nextProps, nextState) {
        console.log(this.props, this.state); //目前的props和state
        console.log(nextProps, nextState); //接下要变化的目标props,目标state
        return !(this.props.carName === nextProps.carName);
      }
    
      render() {
        console.log("Child---render");
        return (
          <div className="child">
            <h3>我是Child组件</h3>
            <span>我接到的车是:{this.props.carName}</span>
          </div>
        );
      }
    }
    

    运行结果:
    在这里插入图片描述
    在这里插入图片描述

  • 办法2:

    • 使用PureComponent

    • PureComponent重写了shouldComponentUpdate(), 只有state或props数据有变化才返回true

      项目中一般使用PureComponent来优化

    代码案例片段:

    import React, { PureComponent } from "react";
    import "./index.css";
    
    export default class Parent extends PureComponent {
      state = { carName: "奔驰c36", stus: ["小张", "小李", "小王"] };
    
      addStu = () => {
        const { stus } = this.state;
        this.setState({ stus: ["小刘", ...stus] });
      };
    
      changeCar = () => {
        this.setState({ carName: "迈巴赫" });
      };
    
      render() {
        console.log("Parent---render");
        const { carName } = this.state;
        return (
          <div className="parent">
            <h3>我是Parent组件</h3>
            {this.state.stus}&nbsp;
            <span>我的车名字是:{carName}</span>
            <br />
            <button onClick={this.changeCar}>点我换车</button>
            <button onClick={this.addStu}>添加一个小刘</button>
            <Child carName={carName} />
          </div>
        );
      }
    }
    
    class Child extends PureComponent {
    
      render() {
        console.log("Child---render");
        return (
          <div className="child">
            <h3>我是Child组件</h3>
            <span>我接到的车是:{this.props.carName}</span>
          </div>
        );
      }
    }
    

    运行结果:
    在这里插入图片描述
    在这里插入图片描述

    注意:

    • 只是进行state和props数据的浅比较, 如果只是数据对象内部数据变了, 返回false

    • 不要直接修改state数据, 而是要产生新数据


五、render props

5.1 如何向组件内部动态传入带内容的结构(标签)?

Vue中:

  • 使用slot技术, 也就是通过组件标签体传入结构 <AA><BB/></AA>

React中:

  • 使用children props: 通过组件标签体传入结构
  • 使用render props: 通过组件标签属性传入结构, 一般用render函数属性

5.2 children props

<A>
  <B>xxxx</B>
</A>
{this.props.children}
问题: 如果B组件需要A组件内的数据, ==> 做不到 

5.3 render props

<A render={(data) => <C data={data}></C>}> </A>
A组件: {this.props.render(内部state数据)}
C组件: 读取A组件传入的数据显示 {this.props.data}

代码案例片段:

import React, { Component } from "react";
import "./index.css";

export default class Parent extends Component {
  render() {
    return (
      <div className="parent">
        <h3>我是Parent组件</h3>
        <A render={(name) => <B name={name} />} />
      </div>
    );
  }
}

class A extends Component {
  state = { name: "tom" };
  render() {
    console.log("A--render", this.props);
    const { name } = this.state;
    return (
      <div className="a">
        <h3>我是A组件</h3>
        {this.props.render(name)}
      </div>
    );
  }
}

class B extends Component {
  render() {
    console.log("B--render", this.props);
    return (
      <div className="b">
        <h3>我是B组件,{this.props.name}</h3>
      </div>
    );
  }
}

运行结果:
在这里插入图片描述


六、错误边界

6.1 理解:

错误边界: 用来捕获后代组件错误,渲染出备用页面

6.2 特点:

只能捕获后代组件生命周期产生的错误,不能捕获自己组件产生的错误和其他组件在合成事件、定时器中产生的错误

使用方式:

getDerivedStateFromError配合componentDidCatch

// 生命周期函数,一旦后台组件报错,就会触发
static getDerivedStateFromError(error) {
    console.log(error);
    // 在render之前触发
    // 返回新的state
    return {
        hasError: true,
    };
}

componentDidCatch(error, info) {
    // 统计页面的错误。发送请求发送到后台去
    console.log(error, info);
}

代码案例片段:

Children.jsx

import React, { Component } from "react";

export default class Child extends Component {
  state = {
    // users:[
    // 	{id:'001',name:'tom',age:18},
    // 	{id:'002',name:'jack',age:19},
    // 	{id:'003',name:'peiqi',age:20},
    // ]
    users: "abc",
  };

  render() {
    return (
      <div>
        <h2>我是Child组件</h2>
        {this.state.users.map((userObj) => {
          return (
            <h4 key={userObj.id}>
              {userObj.name}----{userObj.age}
            </h4>
          );
        })}
      </div>
    );
  }
}

Parent.jsx

import React, { Component } from 'react'
import Child from './Child'

export default class Parent extends Component {

	state = {
		hasError:'' //用于标识子组件是否产生错误
	}

	//当Parent的子组件出现报错时候,会触发getDerivedStateFromError调用,并携带错误信息
	static getDerivedStateFromError(error){
		console.log('@@@',error);
		return {hasError:error}
	}

	componentDidCatch(){
		console.log('此处统计错误,反馈给服务器,用于通知编码人员进行bug的解决');
	}

	render() {
		return (
			<div>
				<h2>我是Parent组件</h2>
				{this.state.hasError ? <h2>当前网络不稳定,稍后再试</h2> : <Child/>}
			</div>
		)
	}
}

运行结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/162241.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

本周推荐 | AB实验低响应情景解决实践

推荐语&#xff1a;本文针对AB实验低响应情景下的增量效果不显著问题&#xff0c;提出通过倾向得分匹配方案来衡量策略增量效果的方法&#xff0c;并将相关方案融入一休平台科学评估体系中。文章理论与实践相结合&#xff0c;深入浅出&#xff0c;强烈推荐。——大淘宝技术数据…

9个非常有趣的HTML5 Canvas动画特效合集

HTML5技术正在不断的发展和更新&#xff0c;越来越多的开发者也正在加入HTML5阵营&#xff0c;甚至在移动开发上HTML5的地位也是越来越重要了。HTML5中的大部分动画都是通过Canvas实现&#xff0c;因为Canvas就像一块画布&#xff0c;我们可以通过调用脚本在Canvas上绘制任意形…

计算机视觉OpenCv学习系列:第一部分、绪论

第一部分、绪论第一节、计算机视觉发展历程1.计算机视觉发展历史2.计算机视觉的主要任务3.计算机视觉的应用场景第二节、计算机视觉框架1.早期计算机视觉框架概述2.当前主流的框架与路线3.计算机视觉框架的未来趋势第三节、OpenCV框架1.OpenCV的发展历史2.OpenCV模块架构3.Open…

深入理解Disruptor

Disruptor通过缓存行填充&#xff0c;利用CPU高速缓存&#xff0c;只是Disruptor“快”的一个因素&#xff0c;快的另一因素是“无锁”&#xff0c;尽可能发挥CPU本身的高速处理性能。 1 缓慢的锁 Disruptor作为一个高性能的生产者-消费者队列系统&#xff0c;核心就是通过Ri…

面向对象的好处

提到面向对象的好处&#xff0c;一些人脑中可能会冒出&#xff1a;封装继承多态封装 封装&#xff1a;通过类&#xff0c;为数据和方法&#xff0c;提供统一的上下文 但是&#xff0c;函数名&#xff0c;同样也可以提供上下文&#xff0c;并且可以通过一种叫柯里化的技巧&…

比特位计数[动态规划 || bitCount计数]

二进制计数前言一、二进制计数二、动态规划 & bitCount分治统计1、bitCount分治统计2、动态规划总结参考文献前言 二进制计数可以直接基于分治去快速统计&#xff0c;如果是连续数的二进制计数&#xff0c;可以利用前面已经计算出的状态进行递推求解&#xff0c;即动态规划…

Python NumPy 连接数组

前言NumPy&#xff08;Numerical Python的缩写&#xff09;是一个开源的Python科学计算库。使用NumPy&#xff0c;就可以很自然地使用数组和矩阵。NumPy包含很多实用的数学函数&#xff0c;涵盖线性代数运算、傅里叶变换和随机数生成等功能。本文主要介绍Python NumPy 连接数组…

使用Java为何总写出C风格的代码?

“你看你所有代码都是把字段取出来计算&#xff0c;然后&#xff0c;再塞回去。各种不同层面的业务计算混在一起&#xff0c;将来有一点调整&#xff0c;所有代码都得跟着变。” 在实际的开发过程中&#xff0c;有不少人都这么写代码的。Java写的代码应该有Java的风格&#xf…

Karl Guttag:Quest Pro透视效果差,并不适合商用

AR/VR光学专家Karl Guttag曾指出&#xff0c;基于VST透视的AR虽然绕开了光学透视AR的一些局限&#xff0c;但VST透视依然存在运动延迟、余光视觉透视效果、分辨率、IPD不匹配等多种问题。的确&#xff0c;VST透视AR的结构、原理比光学透视AR更简单&#xff0c;但它同样需要解决…

(二十)正则表达式

目录 前言: 1.概述: 2.正则表达式体验: 3.正则表达式字符 4.正则表达式在字符串方法中的使用 5.代码演示: 6.正则表达式支持爬取信息 7.代码演示: 前言: 正则表达式&#xff0c;又称规则表达式,&#xff08;Regular Expression&#xff0c;在代码中常简写为regex、regex…

SpringCloud-Netflix学习笔记05——Eureka模拟实现简单集群

前言 对于Eureka注册中心来说&#xff0c;如果只有一个注册中心的话&#xff0c;如果注册中心崩了&#xff0c;那么里面的服务全部用不了&#xff0c;系统就会崩溃。为了避免这个问题&#xff0c;我们可以搭建一个注册中心的集群&#xff0c;几个注册中心互相关联&#xff0c;如…

程序员别死背面试八股文了,这种面试题才是未来主流。。。

目录&#xff1a; 面试官为啥要出这样一个开放式问题生产消费模型及核心数据结构支撑TB级数据写入的分布式架构数据宕机场景下的高可用架构支持数据不丢失的ack机制最后的总结 1、面试官为啥要出这样一个开放式问题 这篇文章简单给大家来聊一个互联网大厂的Java面试题&#x…

【Git 从入门到精通】一文摸透Git中的分支操作

文章目录一、什么是分支&#xff1f;二、分支中的常用命令三、上手分支1.查看分支2.创建分支3.修改分支4.切换分支5.合并分支6.解决冲突四、分支操作原理分析一、什么是分支&#xff1f; 在版本控制过程中&#xff0c;同时推进多个任务&#xff0c;为每个任务&#xff0c;我们…

肠道核心菌——戴阿利斯特杆菌属 (Dialister)

谷禾健康 戴阿利斯特杆菌属 &#xff08;Dialister&#xff09; ✦ Dialister&#xff08;戴阿利斯特杆菌属&#xff09;是小的、厌氧或微需氧的革兰氏阴性球状或杆状菌&#xff0c;因次也被翻译成小杆菌属。 Dialister菌是人体肠道菌群中的一种常见菌种。该菌属物种被发现出现…

基于 Hutool 的抽奖实现与原理

前言 先大概描述下 hutool 工具是如何根据权重进行抽取&#xff0c;后面再结合源码进行讲解。 假设有如下奖品以及对应的权重&#xff1a; 奖品名称权重奖品数量谢谢参与0.76010积分0.4550IPhone 140.055Mac Book Air0.011 需要注意 谢谢参与 也算是一种奖品&#xff0c;因为…

SpringCloud-Netflix学习笔记04——Eureka注册中心搭建

前言 Eureka注册中心相当于Zookeeper注册中心&#xff0c;思想是类似的&#xff0c;只不过Zookeeper需要在本机上下载一个服务客户端&#xff0c;直接启动客户端即可&#xff0c;而Eureka注册中心需要我们自己动手搭建&#xff0c;不过也不难。 搭建步骤 1、新建一个Maven项目…

PySpark数据计算中常用的成员方法(算子)

目录 一.回顾 二.数据计算 map算子 演示 flatMap算子 演示 reduceByKey算子 演示 练习案例1 需求 解决步骤 完整代码 filter算子 演示 distinct算子 演示 sortBy算子 演示 练习案例2 解决步骤 完整代码 三.总结 一.回顾 1.RDD对象是什么?为什么要使用它? RDD对象称…

SegFormer学习笔记(1)安装

一、源码&#xff1a;https://github.com/sithu31296/semantic-segmentation我并没使用SegFormer的官方源码&#xff0c;那个mmcv特磨人了&#xff0c;各种奇葩配置错误。二、环境配置新建conda环境conda create -n segformer3715 python3.7.15 选用python3.7.15(纯粹的3.7.0版…

计算机原理四_内存管理

目录儿三、内存管理3.1 内存管理基础3.1.1存储器的多层结构3.1.2 进程运行基本原理进程的装入3.1.3 内存扩充3.1.4 内存的分配3.1.4.1连续分配3.1.4.2非连续分配3.1.4.2.1基本分页存储管理3.1.4.2.2基本分段存储管理3.1.4.2.3 段页式管理3.2 虚拟内存管理3.2.1 虚拟内存的概念3…

【BP靶场portswigger-客户端11】跨站点脚本XSS-10个实验(下)

前言&#xff1a; 介绍&#xff1a; 博主&#xff1a;网络安全领域狂热爱好者&#xff08;承诺在CSDN永久无偿分享文章&#xff09;。 殊荣&#xff1a;CSDN网络安全领域优质创作者&#xff0c;2022年双十一业务安全保卫战-某厂第一名&#xff0c;某厂特邀数字业务安全研究员&…