• 07-React Hooks(路由组件懒加载, Context上下文, 组件优化...)


    扩展

    setState

    1. (1). setState(stateChange, [callback])------对象式的setState
    2. 1.stateChange为状态改变对象(该对象可以体现出状态的更改)
    3. 2.callback是可选的回调函数, 它在状态更新完毕、界面也更新后(render调用后)才被调用
    4. (2). setState(updater, [callback])------函数式的setState
    5. 1.updater为返回stateChange对象的函数。
    6. 2.updater可以接收到state和props。
    7. 3.callback是可选的回调函数, 它在状态更新、界面也更新后(render调用后)才被调用。
    8. 总结:
    9. 1.对象式的setState是函数式的setState的简写方式(语法糖)
    10. 2.使用原则:
    11. (1).如果新状态不依赖于原状态 ===> 使用对象方式
    12. (2).如果新状态依赖于原状态 ===> 使用函数方式
    13. (3).如果需要在setState()执行后获取最新的状态数据,
    14. 要在第二个callback函数中读取

    LazyLoader

    路由组件的懒加载

    1. # 导入库
    2. import React, {lazy,Suspense} from 'react';
    3. //1.通过React的lazy函数配合import()函数动态加载路由组件 ===> 路由组件代码会被分开打包
    4. const Login = lazy(()=>import('@/pages/Login'))
    5. //2.通过<Suspense>指定在加载得到路由打包文件前显示一个自定义loading界面
    6. <Suspense fallback={<h1>loading.....</h1>}>
    7. <Switch>
    8. <Route path="/xxx" component={Xxxx}/>
    9. <Redirect to="/login"/>
    10. </Switch>
    11. </Suspense>

    Hooks

    简介

    Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

    useState

    1. /**
    2. * 使用范围: 用于函数式组件, 使函数式组件具备state的能力
    3. * useState的使用方式
    4. * 1: 从react库中引入 useState 函数
    5. * 2: 使用函数创建值引用和方法引用
    6. * 2.1: const [count, setCount] = useState(0)
    7. * 2.2: 调用useState 入参为初次属性初始化的默认值
    8. * 2.3: 返回值为数组,一般使用结构的方式获取回来, 第一个引用为值对象, 第二个引用为该值对象的赋值函数
    9. * 3: 渲染方式, 直接通过 {count} 渲染
    10. * 4: 赋值方式: 调用赋值函数
    11. * 4.1: 入参为值对象修改 setCount(count+1)
    12. * 4.2: 入参为函数修改: setCount(count => count + 1) 函数会有一个入参为当前值对象, 然后需要返回一个新的值对象
    13. */
    14. import React, {useState} from 'react';
    15. function Index(props) {
    16. const [count, setCount] = useState(0)
    17. const add = () => {
    18. // setCount(count+1)
    19. setCount(count => count + 1)
    20. }
    21. return (
    22. <div>
    23. <h2>当前求和为:{count}</h2>
    24. <button onClick={add}>+1</button>
    25. </div>
    26. );
    27. }
    28. export default Index;

    useEffect

    1. /**
    2. * 使用范围: 用于函数式组件, 使函数式组件具备生命周期钩子的能力,可以看做是
    3. * componentDidMount,componentDidUpdate,componentWillUnmount
    4. * 三个生命周期钩子函数的集合
    5. * useEffect的使用方式
    6. * 1: 从react库中引入 useEffect 函数
    7. * 2: 使用函数完成生命周期钩子函数
    8. * -:具体使用看下面注释
    9. *
    10. */
    11. import React, {useState, useEffect} from 'react';
    12. function Index(props) {
    13. // useState
    14. const [count, setCount] = useState(0)
    15. const [sum, setSum] = useState(0)
    16. const [he, setHe] = useState(0)
    17. /**
    18. * 实现componentDidMount
    19. * useEffect 第二个参数[] 什么也不写, 就是代表不监听任何state的变化, 只有在第一次渲染的时候执行
    20. */
    21. useEffect(() => {
    22. // setCount(count+1)
    23. // 实现count自动累加
    24. const timer = setInterval(() => {
    25. // 这里有个问题, 需要使用函数式入参, 不能直接使用值入参, 因为值入参是异步的, 函数的话会接受到上一次的值
    26. setCount(count => count + 1)
    27. }, 1000)
    28. }, [])
    29. /**
    30. * 实现componentDidMount+componentDidUpdate
    31. * useEffect 第二个参数[] 里面写了那些state的值对象, 当这些值对象发生变化时,就会执行这个函数
    32. */
    33. useEffect(() => {
    34. //count改变的时候sum自动加1
    35. if (count !== 0) {
    36. setSum(sum => sum + 1)
    37. }
    38. }, [count])
    39. /**
    40. * 实现componentDidMount+componentDidUpdate+componentWillUnmount
    41. * useEffect 函数, 可以返回一个函数, 这个返回的函数就是componentWillUnmount生命周期钩子, 所有清除定时器,取消订阅等操作就可以写在这个函数里面
    42. */
    43. useEffect(() => {
    44. //count改变的时候sum自动加1
    45. const timer = setInterval(() => {
    46. // 这里有个问题, 需要使用函数式入参, 不能直接使用值入参, 因为值入参是异步的, 函数的话会接受到上一次的值
    47. setHe(he => he + 1)
    48. }, 1000)
    49. return () => {
    50. clearInterval(timer)
    51. }
    52. }, [])
    53. return (
    54. <div>
    55. <h2>当前求和为:{count}</h2>
    56. <h2>当前求和为:{sum}</h2>
    57. <h2>当前求和为:{he}</h2>
    58. </div>
    59. );
    60. }
    61. export default Index;

    useRef

    1. /**
    2. * 使用范围: 用于函数式组件, 使函数式组件具备React.createRef的能力
    3. * useRef的使用方式
    4. * 1: 从react库中引入useRef函数
    5. * 2: 使用函数创建属性 const myRef = useRef()
    6. * 3: 绑定到组件
    7. * 4: 获取值 myRef.current.value
    8. */
    9. import React, {useRef} from 'react';
    10. function Index(props) {
    11. const myRef = useRef()
    12. const show = () => {
    13. console.log(myRef.current.value)
    14. }
    15. return (
    16. <div>
    17. <input ref={myRef} type="text"/>
    18. <button onClick={show}>显示</button>
    19. </div>
    20. );
    21. }
    22. export default Index;

    Fragment

    1. /**
    2. * Fragment : 代码片段标签, 在React渲染时会被丢弃
    3. * 使用方式:
    4. * 1: 从react库中引入
    5. * 2: 一般包裹在最外层
    6. * 3: 只接受唯一一个属性 key
    7. * 4: 如不过想写, 可以使用空标签替换 <>
    8. */
    9. import React, {Fragment} from 'react';
    10. function Index(props) {
    11. return (
    12. <Fragment key={'fg'}>
    13. <h2>代码片段:</h2>
    14. </Fragment>
    15. );
    16. }
    17. export default Index;

    Context+useContext(Hooks)

    1. /**
    2. * Context: 上下文对象, 一般用于多层次组件传递值
    3. * 使用方式:
    4. * 1: 从react中引入React
    5. * 2: 创建: const UserNameContext = createContext('dance')
    6. * -: 看下方注释
    7. */
    8. import React, {Component, useState, useContext, createContext} from 'react';
    9. // 创建Context对象
    10. const UserNameContext = createContext('dance')
    11. function Main(props) {
    12. const [userName, setUserName] = useState('tom');
    13. return (
    14. <>
    15. <h2>我是Main组件</h2>
    16. <h3>我的用户名是:{userName}</h3>
    17. <hr/>
    18. {/* 通过value属性传入参数, 所有的子组件就都可以获取到context */}
    19. <UserNameContext.Provider value={userName}>
    20. <A/>
    21. </UserNameContext.Provider>
    22. </>
    23. );
    24. }
    25. function A(props) {
    26. return (
    27. <>
    28. <h2>我是A组件</h2>
    29. {/* 通过标签Consumer获取,并渲染 */}
    30. <UserNameContext.Consumer>
    31. {
    32. value => (<h3>接受到的用户名是:{value}</h3>)
    33. }
    34. </UserNameContext.Consumer>
    35. <hr/>
    36. <B/>
    37. </>
    38. );
    39. }
    40. /**
    41. * 函数式组件接受Context
    42. */
    43. function B(props) {
    44. // 通过useContext函数获取,并渲染
    45. let context = useContext(UserNameContext)
    46. return (
    47. <>
    48. <h2>我是B组件</h2>
    49. <h3>接受到的用户名是:{context}</h3>
    50. <C/>
    51. </>
    52. );
    53. }
    54. /**
    55. * 类组件 接受Context
    56. */
    57. class C extends Component {
    58. // 类组件通过属性获取,并渲染
    59. static contextType = UserNameContext
    60. render() {
    61. return (
    62. <>
    63. <h2>我是C组件</h2>
    64. <h3>接受到的用户名是:{this.context}</h3>
    65. </>
    66. );
    67. }
    68. }
    69. export default Main;

    组件优化

    Component的两个问题

    1. 只要执行setState(),即使不改变状态数据, 组件也会重新render() ==> 效率低
    2. 只当前组件重新render(), 就会自动重新render子组件,纵使子组件没有用到父组件的任何数据 ==> 效率低

    优化

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

    因为Component中的shouldComponentUpdate()总是返回true

    解决办法

    1. 办法1:
    2. 重写shouldComponentUpdate()方法
    3. 比较新旧state或props数据, 如果有变化才返回true, 如果没有返回false
    4. 办法2:
    5. 使用PureComponent
    6. PureComponent重写了shouldComponentUpdate(), 只有state或props数据有变化才返回true
    7. 注意:
    8. 只是进行state和props数据的浅比较, 如果只是数据对象内部数据变了, 返回false
    9. 不要直接修改state数据, 而是要产生新数据
    10. 项目中一般使用PureComponent来优化

    但是一般项目开发中都是用函数式组件+hooks来写的

    render props

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

    1. Vue中:
    2. 使用slot技术, 也就是通过组件标签体传入结构 <A><B/></A>
    3. React中:
    4. 使用children props: 通过组件标签体传入结构
    5. 使用render props: 通过组件标签属性传入结构,而且可以携带数据,一般用render函数属性

    children props

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

    render props

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

    错误边界

    • 理解:
      • 错误边界(Error boundary):用来捕获后代组件错误,渲染出备用页面
    • 特点:
      • 只能捕获后代组件生命周期产生的错误,不能捕获自己组件产生的错误和其他组件在合成事件、定时器中产生的错误
    • 使用方式:
      • getDerivedStateFromError配合componentDidCatch
    1. // 生命周期函数,一旦后台组件报错,就会触发
    2. static getDerivedStateFromError(error) {
    3. console.log(error);
    4. // 在render之前触发
    5. // 返回新的state
    6. return {
    7. hasError: true,
    8. };
    9. }
    10. componentDidCatch(error, info) {
    11. // 统计页面的错误。发送请求发送到后台去
    12. console.log(error, info);
    13. }

    组件通信方式总结

    组件间的关系:

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

    几种通信方式:

    1. 1.props:
    2. (1).children props
    3. (2).render props
    4. 2.消息订阅-发布:
    5. pubs-sub、event等等
    6. 3.集中式管理:
    7. redux、dva等等
    8. 4.conText:
    9. 生产者-消费者模式

    比较好的搭配方式:

    1. 父子组件:props
    2. 兄弟组件:消息订阅-发布、集中式管理
    3. 祖孙组件(跨级组件):消息订阅-发布、集中式管理、conText(开发用的少,封装插件用的多)
  • 相关阅读:
    传奇开服教程——legend/blue引擎替换和登陆器生成教程
    【深度学习】python调用超分Real-ESRGAN
    【JavaScript 进阶教程】数组新增遍历方法的说明与使用
    1、设计模式的简介
    shap-Basic SHAP Interaction Value Example in XGBoost
    FTP服务详解
    Django中使用Ajax时使用CSRF保护
    .NET8 AOT和JIT的性能,谁更高呢?
    018、集合_应用场景
    python Kalman滤波跟踪(链接整理+理解)
  • 原文地址:https://blog.csdn.net/flowerStream/article/details/126493663