• 《React扩展知识一》setState更新状态2种写法/ lazyLoad / Fragment / Context / Hooks


    前言

    博主主页👉🏻蜡笔雏田学代码
    专栏链接👉🏻React专栏
    今天来学习React的一些扩展知识
    下一篇文章也会再介绍另外一些React扩展知识
    感兴趣的小伙伴一起来看看吧~🤞

    在这里插入图片描述

    1. setState

    setState更新状态的2种写法

    1️⃣ setState(stateChange, [callback])------对象式的setState

    • stateChange为状态改变对象(该对象可以体现出状态的更改)
    add = () => {
      // 1.获取原来的count值
      const { count } = this.state
      // 2.更新状态
      this.setState({ count: count + 1 })
      console.log('12行的输出', this.state.count)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    由于setState()是同步的方法, 但是是异步执行的,所以会先打印clg,再更新状态。

    • callback是可选的回调函数, 它在状态更新完毕界面也更新后(render调用后)才被调用
    add = () => {
      // 1.获取原来的count值
      const { count } = this.state
      // 2.更新状态
      this.setState({ count: count + 1 }, () => {
        console.log(this.state.count)
      })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2️⃣ setState(updater, [callback])------函数式的setState

    • updater为返回stateChange对象的函数。
    • updater可以接收到state和props
    • callback是可选的回调函数, 它在状态更新、界面也更新后(render调用后)才被调用。
    this.setState((state, props) => {
      console.log(state, props)
      return { count: state.count + 1 }
    })
    
    • 1
    • 2
    • 3
    • 4

    总结

    1️⃣对象式的setState是函数式的setState的简写方式(语法糖)

    2️⃣使用原则:

    • 如果新状态不依赖于原状态 ===> 使用对象方式
    • 如果新状态依赖于原状态 ===> 使用函数方式
    • 如果需要在setState()执行后获取最新的状态数据, 要在第二个callback函数中读取

    2. lazyLoad

    路由组件的lazyLoad懒加载

    1️⃣引入lazy函数和Suspense组件

    import React, { Component, lazy, Suspense } from 'react';
    
    • 1

    实现路由的懒加载

    2️⃣通过React的lazy函数配合import()函数动态加载路由组件 ===> 路由组件代码会被分开打包

    const Home = lazy(() =>
      import('./Home')
    )
    const About = lazy(() =>
      import('./About')
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3️⃣通过指定在加载得到路由打包文件前显示一个自定义loading界面

    <Suspense fallback={<h1>Loading...</h1>}>
        {/* 注册路由 */}
    		<Route path="/about" component={About} />
      	<Route path="/home" component={Home} />
    </Suspense>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3. Hooks

    上两篇文章着重讲解了React Hooks基础React Hooks进阶,在此简单概括一下:

    React Hook/Hooks是什么?

    Hook是React 16.8.0版本增加的新特性/新语法

    可以让你在函数组件中使用 state 以及其他的 React 特性

    三个常用的Hook

    State Hook: React.useState()

    Effect Hook: React.useEffect()

    Ref Hook: React.useRef()

    State Hook

    State Hook让函数组件也可以有state状态, 并进行状态数据的读写操作

    语法: const [xxx, setXxx] = React.useState(initValue初始值)

    🔥useState()说明:

    ​ 1️⃣参数: 第一次初始化指定的值在内部作缓存

    ​ 2️⃣返回值: 包含2个元素数组, 第1个内部当前状态值, 第2个更新状态值的函数(方法)

    🔥setXxx()2种写法:

    ​ 1️⃣setXxx(newValue): 参数为非函数值, 直接指定新的状态值, 内部用其覆盖原来的状态值

    ​ 2️⃣setXxx(value => newValue): 参数为函数, 接收原本的状态值, 返回新的状态值, 内部用其覆盖原来的状态值

    function Demo() {
      // 返回值第1个为内部当前状态值, 第2个为更新状态值的函数(方法)
      const [count, setCount] = React.useState(0)
      const [name, setName] = React.useState('tom')
    
      // 加的回调
      function add() {
        // setCount(count + 1) //第一种写法
        setCount((count) => {  //第二种写法
          return count + 1
        })
      }
    
      function change() {
        setName('jack')
      }
    
      return (
        <div>
          <h2>当前求和为:{count}</h2>
          <h2>我的名字是:{name}</h2>
          <button onClick={add}>点我加1</button>
          <button onClick={change}>点我改名</button>
        </div>
      )
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    Effect Hook

    Effect Hook 可以让你在函数组件中执行副作用操作(用于模拟类组件中的生命周期钩子)

    🔥React中的副作用操作:

    1️⃣发ajax请求数据获取

    2️⃣设置订阅 / 启动定时器

    3️⃣手动更改真实DOM

    🔥语法和说明:

    useEffect(() => { 
      // 在此可以执行任何带副作用操作
      return () => { // 在组件卸载前执行
        // 在此做一些收尾工作, 比如清除定时器/取消订阅等
      }
    }, [stateValue]) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    🔥可以把 useEffect Hook 看做如下三个函数的组合:

      componentDidMount()
      componentDidUpdate()
      componentWillUnmount() 
    
    • 1
    • 2
    • 3
    React.useEffect(() => {
      let timer = setInterval(() => {
        setCount(count => count + 1)
      }, 1000)
      return () => {
        //这个返回的函数相当于componentWillUnmount()
          clearInterval(timer)
        }
      //如果不写数组,会监测任何改变(相当于componentDidMount()和componentDidUpdate())
    }, [])// 如果指定的是[], 回调函数只会在第一次render()后执行(相当于componentDidMount())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Ref Hook

    1️⃣Ref Hook可以在函数组件中存储/查找组件内的标签或任意其它数据

    2️⃣语法: const refContainer = React.useRef()

    3️⃣作用: 保存标签对象,功能与React.createRef()一样

    4. Fragment

    作用

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

    使用

    Demo组件:

    import React, { Component, Fragment } from 'react'
    
    export default class Demo extends Component {
      render() {
        return (
          //Fragment只能拥有key属性
          <Fragment key={1}>
            <input type="text" />
          </Fragment>
    	//这种写法也行,但是这种写法不能写key等属性
          //<>
          //
          //
        )
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    App.jsx:

    import React, { Component, Fragment } from 'react'
    import Demo from './components/5_Fragment'
    
    export default class App extends Component {
      render() {
        return (
          <Fragment>
            <Demo />
          </Fragment>
        )
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    5. Context

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

    使用

    1️⃣创建Context容器对象:

    const XxxContext = React.createContext()  
    
    • 1

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

    <XxxContext.Provider value={数据}>
      子组件
    </XxxContext.Provider>
    
    • 1
    • 2
    • 3

    3️⃣后代组件读取数据:

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

    示例

    祖组件A想要给孙组件C传递数据: 用户名和年龄

    在这里插入图片描述

    import React, { Component } from 'react'
    import './index.css'
    
    // 创建Context对象
    const MyContext = React.createContext()
    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>
            <MyContext.Provider value={{ username, age }}>
              <B />
            </MyContext.Provider>
          </div>
        )
      }
    }
    
    class B extends Component {
      render() {
        return (
          <div className='child'>
            <h3>我是B组件</h3>
            <C />
          </div>
        )
      }
    }
    
    //孙组件为类组件
    class C extends Component {
      // 声明接收context
      static contextType = MyContext
      render() {
        // 打印出后代组件的this显示出后代组件的context
        console.log(this.context)
        return (
          <div className='grand'>
            <h3>我是C组件</h3>
            <h4>我从A组件接收到的用户名是:{this.context.username},年龄是:{this.context.age}</h4>
          </div>
        )
      }
    }
    
    //孙组件为函数组件
    function C() {
      return (
        <div className='grand'>
          <h3>我是C组件</h3>
          <h4>我从A组件接收到的用户名是:
            <MyContext.Consumer>
              {
                value => {
                  return `${value.username},年龄是${value.age}`
                }
              }
            </MyContext.Consumer>
          </h4>
        </div>
      )
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    注意

    在应用开发中一般不用context, 一般都用它封装react插件, react-redux库底层使用了context.

    今天的分享就到这里啦✨ \textcolor{red}{今天的分享就到这里啦✨} 今天的分享就到这里啦

    原创不易,还希望各位大佬支持一下 \textcolor{blue}{原创不易,还希望各位大佬支持一下} 原创不易,还希望各位大佬支持一下

    🤞 点赞,你的认可是我创作的动力! \textcolor{green}{点赞,你的认可是我创作的动力!} 点赞,你的认可是我创作的动力!

    ⭐️ 收藏,你的青睐是我努力的方向! \textcolor{green}{收藏,你的青睐是我努力的方向!} 收藏,你的青睐是我努力的方向!

    ✏️ 评论,你的意见是我进步的财富! \textcolor{green}{评论,你的意见是我进步的财富!} 评论,你的意见是我进步的财富!

  • 相关阅读:
    排序算法:选择排序,分别用c++、java、python实现
    【定语从句练习题】That 、who、whom、省略
    java生成excel,uniapp微信小程序接收excel并打开
    啥,要我前端去对接外部?我也不会呀
    MacM1 AndroidStudio 自带模拟器安装不上apk
    Markdown还能这么玩?这款开源神器绝了
    TCP延申
    在VR全景中嵌入3D模型有哪些优势?
    [工业互联-6]:PLC工业控制系统快速概览
    Spark杂谈
  • 原文地址:https://blog.csdn.net/xuxuii/article/details/126255881