09_React 扩展

news2024/9/23 22:25:03

React 扩展

  • 一、 setState
    • setState 更新状态的 2 种写法
  • 二、lazyLoad
    • 路由组件的 lazyLoad
  • 三、Hooks
    • 1、React Hook/Hooks 是什么?
    • 2、三个常用的 Hook
    • 3、State Hook
    • 4、Effect Hook
    • 5、Ref Hook
  • 四、Fragment
  • 五、Context
    • 1、理解
    • 2、使用
    • 3、注意
    • 4、代码
  • 六、组件优化
    • 1、Component 的 2 个问题
    • 2、效率高的做法
    • 3、原因
    • 4、解决
      • 4.1 自己重写 “阀门”
      • 4.2 使用 PureComponent 优化
  • 七、render props
    • 1、如何向组件内部动态传入带内容 的结构(标签)?
    • 2、children props
    • 3、render props
    • 4、代码展示
  • 八、错误边界
    • 1、理解:
    • 2、特点
      • 使用方式
  • 九、组件通信方式总结
    • 1、组件间的关系
    • 2、几种通信方式
      • 2.1 props
      • 2.2 消息订阅-发布
      • 2.3 集中式管理
      • 2.4 context
    • 3、比较好的搭配方式

一、 setState

setState 更新状态的 2 种写法

(1)setState(stateChange,[callback]) ---- 对象式的 setState
    1、stateChange 为状态改变对象(该对象可以体现出状态的更改)
    2、callback 是可选的回调函数,它在状态更新完毕,界面也更新后(render调用后)才被调用

(2)setState(updater, [callback]) ---- 函数式的 setState
    1、updater 为返回 stateChange 对象的函数
    2、updater 可以接收到 state 和 props
    3、callback 是可选的回调函数,它在状态更新、界面也更新后(render 调用后)才被调用

总结:
    1、对象式的 setState 是函数式的 setState 的简写方式(语法糖)
    2、使用原则:
        (1)如果新状态不依赖于原状态(跟之前的值完全没有关系) ====> 使用对象方式
        (2)如果新状态依赖于原状态(需要根据之前的值来处理) =====> 使用函数方式
        (3)如果需要在 setState() 执行后获取最新状态数据,要在第二个 callback 函数种读取
import React, { Component } from 'react'

export default class Demo extends Component {
  state = {
    count: 0,
  }
  add = () => {
    // 对象式的 setState
    // const {count} = this.state
    // this.setState({count: count+1},()=>{
    //   console.log(this.state.count)
    // })
    // console.log("", this.state.count)

    // 函数式的 setState
    this.setState((state, props) => {
      console.log(state, props)
      return { count: state.count + 1 }
    })
  }
  render() {
    return (
      <div>
        <h2>当前求和为: {this.state.count}</h2>
        <button onClick={this.add}>点我+1</button>
      </div>
    )
  }
}

二、lazyLoad

路由组件的 lazyLoad

// 1、通过 React 的lazy 函数配合 import() 函数动态加载路由组件===>路由组件代码会被分开打包
const Login = lazy(()=>import('@/pages/Login'))
// 2、通过 <Suspense> 指定在加载得到路由打包文件前显示一个自定义 loading 界面
<Suspense fallback={<h1>loading...</h1>}>
  <Route path='/about' component= {About} />
  <Route path='/home' component= {Home} />
</Suspense>

完整 index 代码

import React, { Component, lazy, Suspense } from 'react'
import { BrowserRouter, Route } from 'react-router-dom'
// import Home from "./pages/Home"
// import About from "./pages/About"
import Header from './components/Header'
import MyNavLink from './components/MyNavLink'

import './index.css'
const Home = lazy(() => import('./pages/Home'))
const About = lazy(() => import('./pages/About'))

export default class Demo extends Component {
  render() {
    return (
      <BrowserRouter>
        <div>
          <Header />
          <div className="row">
            <div className="sidebar">
              <MyNavLink to="/about">About</MyNavLink>
              <MyNavLink to="/home">Home</MyNavLink>
            </div>
            <div className="panel">
              <Suspense fallback={<h1>loading</h1>}>
                <Route path="/about" component={About} />
                <Route path="/home" component={Home} />
              </Suspense>
            </div>
          </div>
        </div>
      </BrowserRouter>
    )
  }
}

三、Hooks

1、React Hook/Hooks 是什么?

(1)Hook 是 React16.8.0 版本增加的新特性/新语法
(2)可以让你在函数组件中使用 state 以及其他的 React 特性

2、三个常用的 Hook

(1)State Hook: React.useState()
(2)Effect Hook:React.useEffect()
(3)Ref Hook: React.useRef()

3、State Hook

(1)State Hook 让函数组件也可以有 state 状态,并进行状态数据的读写操作
(2)语法:const [xxx, setXxx] = React.useState(initValue)
(3)useState() 说明:
参数:第一次初始化指定的值在内部作缓存
返回值:包含 2 个元素的数组,第 1 个为内部当前状态值,第 2 个为更新状态值得函数
(4)setXxx() 2 种写法:
setXxx(newValue):参数为非函数值,直接指定新的状态值,内部用其覆盖原理啊的状态值
setXxx(value=>newValue):参数为函数,接收原本的状态值,返回新的状态值,内部用其覆盖原来的状态值

import React from 'react'

// 函数式组件
function Demo() {
  const [count, setCount] = React.useState(0)
  const [name, setName] = React.useState('Tom')
  console.log(count, setCount)
  function add() {
    console.log('点击了加号')
    // setCount(count+1) // 第一种写法
    setCount((count) => {
      return count + 1
    })
  }
  function changeName() {
    setName('Jack')
  }
  return (
    <div>
      <h2>当前求和为: {count}</h2>
      <h2>我的名字是: {name}</h2>
      <button onClick={add}>点我+1</button>
      <button onClick={changeName}>点我改名字</button>
    </div>
  )
}

4、Effect Hook

(1)Effect Hook 可以让你在函数组件中执行副作用操作(用于模拟类组件中的生命周期钩子)
(2)React 中的副作用操作:
发 ajax 请求数据获取
设置订阅/启动定时器
手动更改真实 DOM
(3)语法和说明:
useEffect(()=>{
// 在此可以执行任何带副作用的操作
return ()=>{// 在组件卸载前执行
//在此做一些收尾工作,比如清楚定时器/取消订阅等
}
}, [stateValue])// 如果指定是 [],回调函数只会在第一次 render() 后执行
(4)可以把 useEffect Hook 看做如下三个钩子函数的组合
componentDidMount()
componentDidUpdate()
componentWillUnmount()

5、Ref Hook

(1)Ref Hook 可以在函数组件中存储/查找组件内的标签或任意其他数据
(2)语法:const refContainer = useref()
(3)作用:保存标签对象,功能与 React.createRef() 一样

四、Fragment

Fragment 的层级最终会被丢弃,不会被渲染为真实 dom
使用

<Fragment></Fragment> // 可以被忽略,但是允许写key属性(并且只能有这个属性)
<></>// 可以被忽略,但是不可以写任何属性

作用
可以不用必须有一个真实的 DOM 根标签了

五、Context

1、理解

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

2、使用

// 1)创建 Context 容器对象:
const XxxContext = React.createContext()
// 2)渲染子组件时,外面包裹 XxxContext.Provider, 通过 value 属性给后代组件传递数据(value 不可以改成其他名字,只能使用 value):
<XxxContext.Provider value={数据}> 子组件 </XxxContext.Provider>
// 3)后代组件读取数据
// 3.1)第一种方式:仅适用于类组件
static contextType = xxxContext // 声明接收 context
this.context // 读取context 中的 value 数据
// 3.2)第二种方式:函数组件与类组件都可以
<XxxContext.Consumer>
  {
    value => ( // value 就是 context 中的 value 数据
      要显示的内容
    )
  }
</XxxContext.Consumer>

3、注意

在应用开发中一般不用 Context,一般都用它封装 React 插件

4、代码

import React, { Component } from 'react'
import './index.css'
const UsernameContext = React.createContext()
export default class Demo extends Component {
  state = {
    username: 'Tom',
  }
  render() {
    return (
      <div className="grandfather">
        <h1>我是Demo组件</h1>
        <h4>我的用户名是:{this.state.username}</h4>
        <UsernameContext.Provider value={this.state}>
          <A />
        </UsernameContext.Provider>
      </div>
    )
  }
}
class A extends Component {
  render() {
    return (
      <div className="father">
        <h3>我是 A 组件</h3>
        <h4>我从 Demo 组件接收到的用户名:???</h4>
        <B />
      </div>
    )
  }
}
class B extends Component {
  // static contextType = UsernameContext
  // render() {
  //   let {username} = this.context
  //   console.log(this, this.context)
  //   return (
  //     <div className='child'>
  //       <h3>我是 B 组件</h3>
  //       <h4>我从 Demo 组件接收到的用户名:{username}</h4>
  //     </div>
  //   )
  // }
  render() {
    return (
      <div className="child">
        <h3>我是 B 组件</h3>
        <h4>
          我从 Demo 组件接收到的用户名:
          <UsernameContext.Consumer>
            {(value) => value.username}
          </UsernameContext.Consumer>
        </h4>
      </div>
    )
  }
}

// 如果是函数式组件
// function B() {
//   return (
//     <div className="child">
//       <h3>我是 B 组件</h3>
//       <h4>
//         我从 Demo 组件接收到的用户名:
//         <UsernameContext.Consumer>
//           {(value) => `${value.username},年龄${value.age}`}
//         </UsernameContext.Consumer>
//       </h4>
//     </div>
//   )
// }

六、组件优化

1、Component 的 2 个问题

1、只要执行 setState() ,即使不改变状态数据,组件也会重新 render()
2、只当前组件重新 render(),就会自动重新 render 子组件===》效率低

2、效率高的做法

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

3、原因

Component 中的 shouldComponentUpdate() 总是返回 true

4、解决

方法1:
  重写 shouldComponentUpdate() 方法
  比较新旧 state 和 props 数据,如果有变化才返回true,如果没有返回 false

方法2:
  使用 PureComponent
  PureComponent重写 shouldComponentUpdate() 方法, state 和 props 数据,如果有变化才返回true,如果没有返回

注意:
  只是进行 state 和 props 数据的浅比较,如果只是数据对象内部数据变了,返回false
  不要直接修改 state 数据(push、unshift等方法都是直接修改原数组的),而是要产生新数据

项目中一般使用 PureComponent 来优化

4.1 自己重写 “阀门”

import React, { Component } from 'react'

import './index.css'

export default class Parent extends Component {
  state = {
    carname: '奔驰c63',
  }

  changCarname = () => {
    this.setState({ carname: '迈巴赫' })
  }
  shouldComponentUpdate(nextProps, nextState) {
    console.log(nextProps, this.props) // 下一个props 和 当前 props
    console.log(nextState, this.state) // 下一个 state 和当前 state
    return nextState.carname !== this.state.carname
  }
  render() {
    console.log('Parent--render')
    let { carname } = this.state
    return (
      <div className="parent">
        <h3>我是 Parent 组件</h3>
        <span>我的车名字是:{carname}</span>
        <button onClick={this.changCarname}>点我换车</button>
        <Child />
        {/*  carname={carname} */}
      </div>
    )
  }
}
class Child extends Component {
  shouldComponentUpdate(nextProps, nextState) {
    console.log(nextProps, this.props) // 下一个props 和 当前 props
    console.log(nextState, this.state) // 下一个 state 和当前 state
    return nextProps.carname !== this.props.carname
  }
  render() {
    console.log('Child--render')
    return (
      <div className="child">
        我是 Child 组件,
        {/* <span>我接收到的车名称是:{this.props.carname}</span> */}
      </div>
    )
  }
}

4.2 使用 PureComponent 优化

import React, { PureComponent } from 'react'

import './index.css'

export default class Parent extends PureComponent {
  state = {
    carname: '奔驰c63',
  }

  changCarname = () => {
    this.setState({ carname: '迈巴赫' })
  }
  render() {
    console.log('Parent--render')
    let { carname } = this.state
    return (
      <div className="parent">
        <h3>我是 Parent 组件</h3>
        <span>我的车名字是:{carname}</span>
        <button onClick={this.changCarname}>点我换车</button>
        <Child />
        {/*  carname={carname} */}
      </div>
    )
  }
}
class Child extends PureComponent {
  render() {
    console.log('Child--render')
    return (
      <div className="child">
        我是 Child 组件,
        {/* <span>我接收到的车名称是:{this.props.carname}</span> */}
      </div>
    )
  }
}

七、render props

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

Vue 中:
  使用 slot 技术,也就是通过组件标签体传入结构 <A><B/></A>

React 中:
  使用 children props:通过组件标签体传入结构
  使用 render props:通过组件标签属性传入结构,而且可以携带数据,一般用 render 函数属性

2、children props

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

3、render props

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

4、代码展示

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} />}></A>
      </div>
    )
  }
}
class A extends Component {
  state = {
    name: '里斯',
  }
  render() {
    let { name } = this.state
    return (
      <div className="child">
        <h3>我是 A 组件</h3>
        {/* <B /> */}
        {this.props.render(name)}
      </div>
    )
  }
}
class B extends Component {
  render() {
    console.log(this.props, 'B')
    return (
      <div className="child1">
        <h3>我是 B 组件</h3>
      </div>
    )
  }
}

八、错误边界

1、理解:

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

2、特点

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

使用方式

getDerivedStateFromError 配合 componentDidCatch

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

componentDidCatch(error, info) {
  // 统计页面的错误,发送请求发送到后台后
  console.log(error,info)
}
import React, { Component } from 'react'
import Child from './Child'
export default class Parent extends Component {
  state = {
    hasError: '', // 用于标识子组件是否产生错误
  }
  // 当 Parent 的子组件出现任何的报错时,都会调用这个方法,并且携带错误信息
  // 适用生产环境,开发环境只能用一下
  static getDerivedStateFromError(error) {
    console.log(error)
    return {
      hasError: error,
    }
  }
  // 属于生命周期钩子,子组件引发了问题就能够触发
  componentDidCatch() {
    console.log('统计错误次数,反馈给服务器,用于通知编码人员进行 bug 的解决')
  }
  render() {
    return (
      <div>
        <h1>我是 Parent 组件</h1>
        {this.state.hasError ? (
          <h2>当前网络不稳定,请稍后再尝试</h2>
        ) : (
          <Child />
        )}
      </div>
    )
  }
}

九、组件通信方式总结

1、组件间的关系

父子组件
兄弟组件(非嵌套组件)
祖孙组件(跨级组件)

2、几种通信方式

2.1 props

(1)children props
(2)render props

2.2 消息订阅-发布

pubs-sub,event 等等

2.3 集中式管理

redux,dva 等等

2.4 context

生产者-消费者模式

3、比较好的搭配方式

父子组件:props
兄弟组件:消息订阅-发布、集中式管理
祖孙组件(跨级组件):消息订阅-发布、集中式管、conText(开发用的少,封装插件用的多)

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

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

相关文章

【C++】拆分详解 - string类

文章目录 一、为什么学习string类&#xff1f;二、标准库中的string类  1. 定义  2. 常用接口说明     2.1 构造     2.2 容量操作     2.3 访问及遍历操作     2.4 修改操作     2.5 非成员函数 三、OJ练习自测  [1. 仅仅反转字母](https://leetcod…

9.23 My_string.cpp

my_string.h #ifndef MY_STRING_H #define MY_STRING_H#include <iostream> #include <cstring>using namespace std;class My_string { private:char *ptr; //指向字符数组的指针int size; //字符串的最大容量int len; //字符串当前…

华为三折叠一拆,苹果脸被打肿了!

文&#xff5c;琥珀食酒社 作者 | 随风 哎呀 苹果这次脸真是被华为狠狠打肿了 那些高高兴兴买iPhone 16的 东西一收到&#xff0c;脸马上就绿了啊 各种意想不到的问题啊 拆开手机后发现有两处掉漆咱就不说了 第一次滑动iPhone 16 Pro屏幕有响应 再滑动就没有响应了咱也…

【27】C++项目练习

练习1 题目如下 代码如下 .h #pragma once #include <string> using namespace std;class Toy { public:Toy();Toy(string name,int price,string place);~Toy();string getName() const;int getPrice() const;string getPlace() const;void changePrice(float count)…

自己开发的windows服务在虚拟机上不能正常启用

最近开发了个数据采集系统&#xff0c;在我本机上发布、安装是没有问题的&#xff1b;但是在虚拟机上进行安装部署的时候&#xff0c;反馈的错误码是1053&#xff0c;服务不能正常启动。 网上搜索可能的原因&#xff0c;如图&#xff1a; 能引起1053的问题比较多&#xff0c;首…

springboot实战学习笔记(4)(Spring Validation参数校验框架、全局异常处理器)

接着上篇博客学习。上篇博客是已经基本完成用户模块的注册接口的开发。springboot实战学习笔记&#xff08;3&#xff09;(Lombok插件、postman测试工具、MD5加密算法、post请求、接口文档、注解、如何在IDEA中设置层级显示包结构、显示接口中的方法)-CSDN博客本篇博客主要是关…

最新版Visual Studio安装教程(超详细,新手必看)

一、官网下载 这里奉上Visual Studio官方下载地址&#xff1a; https://visualstudio.microsoft.com/zh-hans/downloads/https://visualstudio.microsoft.com/zh-hans/downloads/ 对于我们学习来说&#xff0c;下载第一个社区免费版即可&#xff0c;点击下载。 下载完成以后是…

Kubernetes Pod调度基础(kubernetes)

实验环境依旧是k8s快照&#xff0c;拉取本次实验所需的镜像文件&#xff1b; 然后在master节点上传已经编写好的yaml文件&#xff1b; 然后同步会话&#xff0c;导入镜像&#xff1b; pod控制器&#xff1a; 标签选择器--》标签&#xff1a; 标签&#xff1a; 在Kubernetes&…

还在用windows自带录屏?试试这三款录屏工具

作为一名办公室文员&#xff0c;我经常需要录制电脑屏幕来制作教程或者记录工作流程。在众多的录屏工具中&#xff0c;我尝试了四款不同的录屏工具&#xff0c;包括Windows自带录屏工具。今天&#xff0c;我就来跟大家分享一下我的使用体验&#xff0c;希望能帮助到和我有同样需…

利用代码,玩转腾讯云脱敏服务:Java、Python、PHP案例集

腾讯云数据脱敏服务-数据管理的优势是什么&#xff1f; 腾讯云数据脱敏服务-数据管理 提供了一种高效且灵活的方式来保护敏感数据。其核心优势在于可以在数据处理和传输过程中自动化地执行数据脱敏操作。无论是脱敏信用卡号、身份证号还是其他个人信息&#xff0c;该服务都能精…

Games101笔记-二维Transform变换(二)

1、什么是Transform Transform就是通过一个矩阵&#xff0c;进行缩放、旋转、平移等变换 2、缩放、旋转、切变、平移等基础变换 缩放变换&#xff1a; 反射变换&#xff1a; 切变&#xff1a; 绕原点旋转&#xff1a; 以上都是线性变换&#xff1a; 平移变换&#xf…

线程同步:消费者模型(非常重要的模型)

一.线程同步的概念 线程同步&#xff1a;是指在互斥的基础上&#xff0c;通过其它机制实现访问者对 资源的有序访问。条件变量&#xff1a;线程库提供的专门针对线程同步的机制线程同步比较典型的应用场合就是 生产者与消费者 二、生产者与消费者模型原理 在这个模型中&…

中文文本分词-技术实现

当做语音&文本相关的技术时&#xff0c;经常会涉及到文本的分词实现。以下是对中文的文本简单实现。 一、单个中文句子的分词 import jiebatext_ "我爱我的祖国&#xff01;" # 精确模式 seg_list jieba.cut(text_, cut_allFalse) print("精确模式: &qu…

【51实物与仿真】基于51单片机设计的波形/函数发生器(正弦波、锯齿波、三角波、矩形波,设定频率步进值,改变振幅,LCD显示)——文末完整资料链接

基于51单片机设计的波形函数发生器 演示视频: 功能简介: 1.本设计基于STC89C51/52(与AT89S51/52、AT89C51/52通用,可任选)单片机。 2.LCD1602液晶显示波形种类和频率值(10-100HZ)。 3.按键设置波形种类和设定频率步进值。 4.电位器器改变振幅(0V-3.5V稳定)。 5…

医院预约|基于springBoot的医院预约挂号系统设计与实现(附项目源码+论文+数据库)

私信或留言即免费送开题报告和任务书&#xff08;可指定任意题目&#xff09; 目录 一、摘要 二、相关技术 三、系统设计 四、数据库设计 五、核心代码 六、论文参考 七、源码获取 一、摘要 近年来&#xff0c;信息化管理行业的不断兴起&#xff0c;使得人们的日…

集合根据上下级关系转树结构

1、创建实体对象 public class TreeNode {private String id;private String pid;private String name;private List<TreeNode> children;public TreeNode(String id,String pid,String name){this.id id;this.pid pid;this.name name;}public String getId() {retur…

独立游戏《Project:Survival》UE5C++开发日志0——游戏介绍

该游戏是《星尘异变》团队的下一款作品&#xff0c;太空科幻题材的生存游戏&#xff0c;我将负责使用C、蓝图实现游戏的基础框架和核心功能&#xff0c;其中还包含使用人工智能算法助力游戏开发或帮助玩家运营 目前已有功能&#xff1a; 1.3D库存系统&#xff1a;所有库存中的物…

Python练习宝典:Day 3 - 选择题 - 字符串与正则表达式、基础练习补充

目录 一、基础练习补充二、字符串与正则表达式 一、基础练习补充 1.下列能返回变量s的数据类型的是: A.print(type(s)) B.print(s) C.print(int(s)) D.print(str(s))2.如果想要换行,可以使用: A.\ B.\n C.\t D.\f3.合法的标识符是: A.M-N B.and C.Dior_Ysl D.6_friends4.在…

计算机毕业设计springboot+vue项目分享在线服务平台

目录 功能和技术介绍系统实现截图开发核心技术介绍&#xff1a;使用说明开发步骤编译运行需求分析系统设计软件测试核心代码部分展示详细视频演示源码获取 功能和技术介绍 本项目包含程序源码和MySql脚本和文档,idea开发,支持Eclipse。使用vue的本质是SpringFramework【IoC&am…

【门牌制作 / A】

题目 代码 #include <bits/stdc.h> using namespace std; int main() {int cnt 0;for (int i 1; i < 2020; i){string s;s to_string(i);cnt count(s.begin(), s.end(), 2);}cout << cnt; }