• React---组件进阶


    组件通讯

    多个组件之间进行数据共享就叫做组件通讯。
    组件通讯通过props和context来实现

    props

    基本使用

    props是用于接受外部传递给组件的数据。

    props是通过给标签添加属性的方式来床底数据。
    在函数组件中通过props参数接受,类组件中通过this.props来接收,props是一个对象。

    特点

    • 可以传递任意类型的数据(基本类型、引用类型、jsx),默认会传递字符串,非字符串要用插值表达式包裹。
    • props的属性是只读的
    • 使用类组件时如果使用了构造器函数,应该把props传递给super(),否则无法获取到props

    深入

    children属性

    • 在使用标签时如果标签内有子节点,props就是自动获得children属性,属性的内柔就是子节点的内容,
    • children属性和props一样都可以传入任意数据类型(基本类型,引用类型,jsx),它是一个数组

    props的校验

    React允许在创建组件时指定props属性的类型和格式,可以在传入的数据格式错误时抛出错误信息。

    1. 使用步骤:
    1. 安装prop-types包
      cnpm i props-types
    2. 导入对应的包
      import PropTypes from 'prop-types'
    3. 使用组件名.PropTypes来添加校验规则
      App.PropTypes = {colors: PropTypes.array}
    1. 常见类型:

    array bool func number object string symbol

    1. 必填项

    在设置属性后再添加一项isRequired属性设置为必填项

    getArc: PropTypes.func.isRequired
    
    • 1
    1. 指定特定结构的对象
    option: PropTypes.shape({
    	color: PropTypes.string,
    	fontSize: PropTypes.number
    })
    
    • 1
    • 2
    • 3
    • 4

    默认值

    组件名.defaultProps = {
    	pageSize: 10
    }
    
    • 1
    • 2
    • 3

    通信类型

    父传子

    1. 父组件提供数据
    2. 在子组件标签中添加属性来传值
    3. 子组件内部通过props来接收

    子传父

    1. 父组件提供回调函数
    2. 将回调函数作为属性传递给子组件
    3. 子组件通过props接受回调函数
    4. 子组件定义函数作为父组件回调函数的参数调用
    5. 将要传递的数值作为子组件函数的参数传入

    兄弟组件

    1. 将共享的状态提升到最近的公共父组件中,称为状态提升。
    2. 父组件提供共享的状态和操作状态的方法。
    3. 子组件通过props接收状态和操作方法(按照子传父和父传子的方式)

    context

    如果父子的嵌套层次很深,可以通过context跨层次传递。

    1. 使用React.createContext()来创建提供数据(Provider)和使用数据(Consumer)的两个组件。
    const { Provider , Consumer } = 
    React.createContext();
    
    • 1
    • 2
    1. 使用Provider组件来包裹我们自定义的组件。
    <Provider>
    	<div></div>
    </Provider>
    
    • 1
    • 2
    • 3
    1. 设置value属性设置要传递的数据。
    <Provider value='pink'>
    	<div></div>
    </Provider>
    
    • 1
    • 2
    • 3
    1. 通过Consumer组件接受值
    <Consumer>
    	(data) => <span>这里是数据:{data}</span>
    </Consumer>
    
    • 1
    • 2
    • 3

    生命周期

    只有类组件才有生命周期。
    生命周期图

    组件复用

    组件的复用其实就是复用state和setState,有renderprops和高阶组件两种模式来实现复用。

    render props模式

    思路

    思路:将state和操作state的方法封装到组件中。

    添加一个函数作为props,用这个函数来将组件内部的值公开,通过这个函数的返回值来渲染UI

    代码实现

    在这里插入图片描述

    复用

    刚才是显示鼠标的坐标,这个组件还可以在鼠标位置显示图片充当特殊指针
    这种方式可以实现逻辑的复用,但不能复用UI

    不用修改组件,直接重写UI就可以
    在这里插入图片描述

    children属性

    这样写可读性更强
    在这里插入图片描述
    在这里插入图片描述

    最终优化

    1. 添加检验:类型和必选项
    App.propTypes = {
    	children: PropTypes.func.isRequired
    }
    
    • 1
    • 2
    • 3
    1. 解除事件
      // 卸载组件时解除事件
      componentWillUnmount(){
        window.removeEventListener('mousemove',this.changeMouse)
      }
    
    • 1
    • 2
    • 3
    • 4

    高阶组件模式

    思路

    高阶组件(HOC)实际上是一个函数,接收一个组件,返回一个增强后的组件。
    函数内部提供一个类组件,这个类组件提供可以复用的逻辑代码,通过props将其传递给传入函数的组件。

    使用步骤

    1. 创建with开头的函数。
    2. 指定函数参数(大写字母开头,作为要渲染的组件,这个组件提供Ui结构)。
    3. 函数内部创建类组件,提供可以复用的逻辑代码。
    4. 在类组件中渲染参数组件,同时将状态通过props传递给参数组件。
    5. 返回类组件,这样就有了一个同时包含UI和逻辑代码的组件。
    // 高阶组件函数
    function withMouse (Com) {
      class App extends React.Component {
        state = {
          x: 0,
          y: 0 
        }
        // 鼠标事件
        changeMouse = (e) => {
          this.setState({
            x: e.clientX,
            y: e.clientY
          })
        }
        // 在生命周期中绑定事件
        componentDidMount(){
          window.addEventListener('mousemove',this.changeMouse)
        }
        // 卸载组件时解除事件
        componentWillUnmount(){
          window.removeEventListener('mousemove',this.changeMouse)
        }
        // render
        render(){
          return (<Com {...this.state}></Com>);
        }
      }
      return App;
    }
    // 函数组件
    const Mouse = props => (
        <h1>
          <div>x: {props.x}</div>
          <div>y: {props.y}</div>
        </h1>
      )
    // 调用高阶组件函数
    const StrongMouse = withMouse(Mouse)
    
    • 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

    displayName

    被高阶组件包装的组件在devtools中会显示原始的组件名(高阶组件函数return时的名称),不利于调试。

    // 高阶组件函数
    function withMouse (Com) {
      class App extends React.Component {
        state = {
          x: 0,
          y: 0 
        }
        // 鼠标事件
        changeMouse = (e) => {
          this.setState({
            x: e.clientX,
            y: e.clientY
          })
        }
        // 在生命周期中绑定事件
        componentDidMount(){
          window.addEventListener('mousemove',this.changeMouse)
        }
        // 卸载组件时解除事件
        componentWillUnmount(){
          window.removeEventListener('mousemove',this.changeMouse)
        }
        // render
        render(){
          return (<Com {...this.state}></Com>);
        }
      }
    
      // 设置displayName
      App.displayName = `WithApp${getDiaplayName(Com)}`
      return App;
    }
    
    // 设置displayName的辅助函数,通用
    function getDisplayName (Com) {
      return Com.displayName || Com.Name || 'Component'
    }
    
    • 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

    props传递

    上面的代码中,在高阶组件函数的返回值上直接添加属性是加不上去的,因为这个时候props已经丢失了

    需要在渲染组件时,将state和props一起传递下去

    // 高阶组件函数,最终版本,新增加了props传递
    function withMouse (Com) {
      class App extends React.Component {
        state = {
          x: 0,
          y: 0 
        }
        // 鼠标事件
        changeMouse = (e) => {
          this.setState({
            x: e.clientX,
            y: e.clientY
          })
        }
        // 在生命周期中绑定事件
        componentDidMount(){
          window.addEventListener('mousemove',this.changeMouse)
        }
        // 卸载组件时解除事件
        componentWillUnmount(){
          window.removeEventListener('mousemove',this.changeMouse)
        }
        // render
        render(){
          return (<Com {...this.state} {...this.props}></Com>);
        }
      }
    
    • 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
  • 相关阅读:
    JVM学习-类加载过程(一)
    详谈操作系统中的内核态和用户态
    阿里巴巴找黄金宝箱(II)
    四、cadence ic 617 ——添加工艺库文件
    RocketMQ Promethus Exporter
    P3879 [TJOI2010] 阅读理解题解
    Miniconda:在pycharm的terminal中无法使用Conda命令
    基于LinuxC语言实现的TCP多线程/进程服务器
    连接池优化
    在面试了些外包以后,我有了些自己的思考
  • 原文地址:https://blog.csdn.net/m0_66711291/article/details/126061786