# 一、组件

# 1、组件分类

  通常情况下,组件可以分为:

  • 函数式组件、类组件
  • 无状态组件、有状态组件
  • 展示型组件、容器型组件

# 2、类组件

  关于类组件的高级部分,可以关注 类组件的 render() 返回值类型

import React from 'react'
class Demo extends React.Component {
  //
  render() {
    // 返回 jsx
    return <h1>Hello, world!</h1>

    // 返回数组 或 fragments
    return (
      <>
        <h1>今日新闻</h1>
        <p>lencamo正在学习React</p>
      </>
    )
    return (
      <React.Fragment>
        <h1>今日新闻</h1>
        <p>lencamo正在学习React</p>
      </React.Fragment>
    )
    return [<h1>今日新闻</h1>, <p>lencamo正在学习React</p>]

    // 返回文本节点(字符串、数值)
    return 'Hello, world!'
    return 123

    // 当然,返回undefined、null、Boolean类型会显示为空值
  }
}

export default Demo

# 3、函数式组件

16.8 后伴随着 hooks 的出现,函数式组件的使用率逐渐提高(类似于 vue 中的 components API)

  简单使用:

function Demo(props) {
  // 其支持的返回类型和类组件一样
  return <h1>Hello, world!</h1>
}

export default Demo

  缺点:

  • 没有生命周期
  • 没有组件实例(this 关键字指向问题)
  • 没有内部状态

# 4、受控组件

  在大多数情况下,我们推荐使用 受控组件 来处理表单数;简单的说,就是让相关数据交给 this.state 控制。

当我们对表单组件加上 value 属性,并且其值为 this.state 中的某个值(可以设置默认值),此时该组件为受控组件(由 react 控制)

多表单元素数据监控
  • 批量处理多个输入
class Demo extends React.PureComponent {
  handleChange(event) {
    const value = event.target.type === 'checkbox' ? event.target.checked : event.target.value

    this.setState({
      // 批量监控
      [event.target.name]: value
    })
  }
  //
  render() {
    return (
      <div>
        <input
          type="text"
          name="useranme"
          value={username}
          onChange={(e) => this.handleChange(e)}
        />
        <input
          type="password"
          name="password"
          value={password}
          onChange={(e) => this.handleChange(e)}
        />
        <select value={fruit} onChange={(e) => this.handleChange(e)}>
          <option value="apple">苹果</option>
          <option value="orange">橘子</option>
          <option value="banana">香蕉</option>
        </select>
        <input
          type="checkbox"
          name="checkbox"
          checked={isSelect}
          onChange={(e) => this.handleChange(e)}
        />
      </div>
    )
  }
}
  • 关于 CheckBox 多选

直接弄一个对象数组数据,然后根据该数据进行 map 创建 jsx

class Demo extends React.PureComponent {
  constructor() {
    super()

    this.state = {
      username: ''
    }
  }
  inputChange(event) {
    // console.log(event.target.value)
    this.setState({
      username: event.target.value
    })
  }
  //
  render() {
    const { username } = this.state

    return (
      <div>
        <input type="text" value={username} onChange={(e) => this.inputChange(e)} />
        用户名:{username}
      </div>
    )
  }
}
拓展:非受控组件
class Demo extends React.PureComponent {
  constructor() {
    super()

    this.state = {
      username: ''
    }

    this.usernameRef = React.createRef()
  }

  componentDidMount() {
    // this.usernameRef.current.addEventListener
  }

  //
  render() {
    const { username } = this.state

    return (
      <div>
        <input type="text" defaultValue={username} ref={this.usernameRef} />
        用户名:{this.}
      </div>
    )
  }
}

# 5、高阶组件 ✨

  高阶组件本身不是一个组件,而是一个函数。它接收一个组件作为它的参数,并返回一个新的组件

高阶组件的英文 Higher-Order Components,简称 HOC。本质上就是对原组件进行一次拦截处理。

function hoc(Cpn) {
  class NewCpn extends React.PureComponent {
    //
    render() {
      return <Cpn name="lencamo" />
    }
  }

  // 可以使用displayName修改组件名
  NewCpn.displayName = 'myComponent'

  return NewCpn
}

export default hoc

  高阶组件的应用场景非常广泛,场景的有(第三方库 ):

  • redux 中的 connect
  • react-router 中的 withRouter

提示

  向我们前面提到的在函数式组件中可以使用的 函数memo、函数forwardRef 等,本质上也是一个高阶组件

应用 1:对原组件注入 props(props 增强)
  • 编写高阶组件
function enhancedUserInfo(OriginComponent) {
  class NewComponent extends React.PureComponent {
    constructor() {
      super()

      this.state = {
        userInfo: {
          name: 'lencamo',
          level: 20
        }
      }
    }

    render() {
      // 加上 {...this.props} 是因为高阶组件的调用者 Demo 的调用者App等可能会向Demo传递props
      return <OriginComponent {...this.props} {...this.state.userInfo} />
    }
  }

  return NewComponent
}

export default enhancedUserInfo
  • 使用高阶组件
import  from '@/hoc/enhanced_props.js'

class Demo extends React.PureComponent {
  //
  printProps() {
    console.log(this.props.name, this.props.level)
  }

  render() {
    return (
      <button onClick={() => this.printProps()} >查看props</button>
    )
  }
}

// 对当前组件增强
export default enhancedUserInfo(Demo)
  • Demo 组件的调用者
class App extends React.Component {
  //
  render() {
    return <Demo />
  }
}

export default App
应用 2:xxx.Consumer 封装(Context 共享)
  • 编写高阶组件
import ThemeContext from '@/context/theme-context.js'

// function withTheme(OriginComponent) {
//   return (props) => {
//     return (
//       <ThemeContext.Consumer>
//         {(value) => {
//           return <OriginComponent {...value} {...props} />
//         }}
//       </ThemeContext.Consumer>
//     )
//   }
// }

function withTheme(OriginComponent) {
  class NewComponent extends React.PureComponent {
    //
    render() {
      return (
        <ThemeContext.Consumer>
          {(value) => {
            // 将value作为 props 传递出去
            return <OriginComponent {...value} {...this.props} />
          }}
        </ThemeContext.Consumer>
      )
    }
  }

  return NewComponent
}

export default withTheme
  • 使用高阶组件
import  from '@/hoc/with_theme.js'

class Demo extends React.PureComponent {
  //
  render() {
    // 使用 Provider 传来的value数据
    return <p>this.props.xxx</p>
  }
}

// 对当前组件增强
export default withTheme(Demo)
应用 3:登录鉴权
function loginAuth(OriginComponent) {
  // 从 应用2 中我们可以看到 在没有状态的情况下,使用函数会更加简洁
  return (props) => {
    const token = localStorage.getItem('token')

    if (token) {
      return <OriginComponent {...props} />
    } else {
      return <h2>请先登录</h2>
    }
  }
}

export default loginAuth

# 二、其他

  下面,简单介绍一些 react 中内置的一些高阶组件:

# 1、StrictMode 组件

  StrictMode 和 Fragment 一样,不会渲染任何可见的 UI。要注意的是严格模式检查仅在开发模式下运行;它们不会影响生产构建。

# 2、Fragment 组件

  和 vue3 中的 Fragment 作用一样,没什么好说的。

# 3、Portals 组件

  其实 Portals 的作用类似于 vue3 中的 内置组件 Teleport

ReactDOM.createPortal(child, container)

Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案

import React from 'react'
import { createPortal } from 'react-dom'

class App extends React.PureComponent {
  //
  render() {
    return (
      <h1>Hello, world!</h1>
      {
        createPortal(<h2>放在其他地方</h2>, document.querySelector("#root2"))
      }
    )
  }
}

export default App
应用:居中弹窗
  • 编写弹窗
import { createPortal } from 'react-dom'

class Modal extends React.PureComponent {
  render() {
    // #modal提前编写了居中样式
    return createPortal(this.props.children, document.querySelector('#modal'))
  }
}

export default Modal
  • 使用弹窗
class Demo extends React.PureComponent {
  render() {
    return (
      <div>
        {
          <Modal>
            <h2>我是标题</h2>
            <p>我是内容,呵呵哈哈哈</p>
          </Modal>
        }
      </div>
    )
  }
}
更新于 : 7/8/2024, 10:21:14 AM