• React组件化开发


    1.组件的定义方式

    • 函数组件Functional Component
    • 类组件Class Component

    2.类组件

    1. export class Profile extends Component {
    2. render() {
    3. console.log(this.context);
    4. return (
    5. <div>Profilediv>
    6. )
    7. }
    8. }
    • 组件的名称是大写字符开头(无论类组件还是函数组件)
    • 类组件需要继承自 React.Component
    • 类组件必须实现render函数
    • constructor是可选的,我们通常在constructor中初始化一些数据
    render函数的返回值

    当 render 被调用时,它会检查 this.props 和 this.state 的变化并返回以下类型之一:

    • React 元素:通常通过 JSX 创建
    • 数组或 fragments:使得 render 方法可以返回多个元素
    • Portals:可以渲染子节点到不同的 DOM 子树中
    • 字符串或数值类型:它们在 DOM 中会被渲染为文本节点
    • 布尔类型或 null:什么都不渲染

    3.函数组件

    函数组件是使用function来进行定义的函数,只是这个函数会返回和类组件中render函数返回一样的内容。

    函数组件有自己的特点:

    • 没有生命周期,也会被更新并挂载,但是没有生命周期函数
    • this关键字不能指向组件实例(因为没有组件实例)
    • 没有内部状态(state)

    4.生命周期

    React内部为了告诉我们当前处于哪些阶段,会对我们组件内部实现的某些函数进行回调,这些函数就是生命周期函数:

    • 实现componentDidMount函数:组件已经挂载到DOM上时,就会回调
    • 实现componentDidUpdate函数:组件已经发生了更新时,就会回调
    • 实现componentWillUnmount函数:组件即将被移除时,就会回调
    不常用的生命周期
    • getDerivedStateFromProps:state 的值在任何时候都依赖于 props时使用;该方法返回一个对象来更新state
    • getSnapshotBeforeUpdate:在React更新DOM之前回调的一个函数,可以获取DOM更新前的一些信息(比如说滚动位置)
    • shouldComponentUpdate:可进行state、props、context进行新旧对比,返回true或false进行是否更新组件

    5.组件之间的通信

    • 父组件通过 属性=值 的形式来传递给子组件数据
    • 子组件通过 props 参数获取父组件传递过来的数据

    父组件:

    1. import React from "react"
    2. // import HelloWorld from "./Components/HelloWorld"
    3. import TabControl from './Components/父子组件通信案例'
    4. // import NavBar from './Components/实现插槽一'
    5. // import NavBar from './Components/实现插槽二'
    6. // import TabControl from './Components/作用域插槽'
    7. // import AppHome from "./Components/非父子组件通信-context/AppHome";
    8. class App extends React.Component {
    9. constructor() {
    10. super()
    11. console.log("hello react");
    12. this.state = {
    13. message: "hello react",
    14. isShow: true,
    15. titles: ['流行', '新款', '精选'],
    16. curIndex: 0
    17. }
    18. }
    19. changeText() {
    20. this.setState({
    21. message: 'hello hgf'
    22. })
    23. }
    24. switchText() {
    25. this.setState({
    26. isShow: !this.state.isShow
    27. })
    28. }
    29. switchTab(curIndex){
    30. this.setState({curIndex})
    31. }
    32. render() {
    33. const { titles, curIndex } = this.state
    34. return (
    35. <div>
    36. <TabControl titles={titles} changeTab={(curIndex) => this.switchTab(curIndex)} />
    37. {/* <h2>{titles[curIndex]}h2> */}
    38. {/* <h2>{message}h2> */}
    39. {/* <button onClick={e => this.switchText()}>切换button> */}
    40. {/* {isShow && <HelloWorld/>} */}
    41. {/* <button onClick={e => this.changeText()}>修改文本button> */}
    42. {/* 插槽实现1 */}
    43. {/* <NavBar>
    44. <button>左边button>
    45. <h2>中间部分h2>
    46. <button>右边button>
    47. NavBar> */}
    48. {/* 插槽实现二 */}
    49. {/* <NavBar leftSlot={<button>左按钮button>} centerSlot={<h2>插槽实现二h2>} rightSlot={<button>右按钮button>} /> */}
    50. {/* 作用域插槽 */}
    51. {/* <TabControl titles={titles} itemTypes={(item) => <button>{item}button>} changeTab={(curIndex) => this.switchTab(curIndex)} />
    52. <h2>{titles[curIndex]}h2> */}
    53. {/* 非父子组件通信 */}
    54. {/* <AppHome /> */}
    55. div>
    56. )
    57. }
    58. componentDidMount() {
    59. console.log("component Mount")
    60. }
    61. componentDidUpdate() {
    62. console.log("component Update");
    63. }
    64. }
    65. export default App

    子组件:

    1. import React, { Component } from 'react'
    2. import "./tab-control.css"
    3. export class index extends Component {
    4. constructor() {
    5. super()
    6. this.state = {
    7. curIndex: 0
    8. }
    9. }
    10. changeCurIndex(index) {
    11. this.setState({curIndex: index})
    12. this.props.changeTab(index)
    13. }
    14. render() {
    15. const {titles} = this.props
    16. const {curIndex} = this.state
    17. return (
    18. <div>
    19. <div className='tab-control'>
    20. {
    21. titles.map((item, index) => {
    22. return (
    23. <div className={`item ${index === curIndex ? 'active':''}`} key={item} onClick={e => this.changeCurIndex(index)}>
    24. <span className='text'>{item}span>
    25. div>
    26. )
    27. })
    28. }
    29. div>
    30. div>
    31. )
    32. }
    33. }
    34. export default index

    6.React中实现插槽

    React对于这种需要插槽的情况非常灵活,有两种方案可以实现:

    • 组件的children子元素
    • props属性传递React元素
    方式一:

    1. import React, { Component } from 'react'
    2. import "./style.css"
    3. export class index extends Component {
    4. render() {
    5. const {children} = this.props
    6. return (
    7. <div className='nav-bar'>
    8. <div className='left'>
    9. {children[0]}
    10. div>
    11. <div className='center'>
    12. {children[1]}
    13. div>
    14. <div className='right'>
    15. {children[2]}
    16. div>
    17. div>
    18. )
    19. }
    20. }
    21. // index.propTypes = {
    22. // children: PropTypes.element
    23. // }
    24. export default index
    方式二:

    1. import React, { Component } from 'react'
    2. import "./style.css"
    3. export class index extends Component {
    4. render() {
    5. const {leftSlot, centerSlot, rightSlot} = this.props
    6. return (
    7. <div className='nav-bar'>
    8. <div className='left'>
    9. {leftSlot}
    10. div>
    11. <div className='center'>
    12. {centerSlot}
    13. div>
    14. <div className='right'>
    15. {rightSlot}
    16. div>
    17. div>
    18. )
    19. }
    20. }
    21. // index.propTypes = {
    22. // children: PropTypes.element
    23. // }
    24. export default index

    7.context应用场景

    非父子组件数据的共享:

    对于有一些场景:比如一些数据需要在多个组件中进行共享(地区偏好、UI主题、用户登录状态、用户信息等)

    • React提供了一个API:Context
    • Context 提供了一种在组件之间共享此类值的方式,而不必显式地通过组件树的逐层传递 props
    • Context 设计目的是为了共享那些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言
    Context相关API:
    React.createContext
    • 创建一个需要共享的Context对象

    • 如果一个组件订阅了Context,那么这个组件会从离自身最近的那个匹配的 Provider 中读取到当前的context值
    • defaultValue是组件在顶层查找过程中没有找到对应的Provider,那么就使用默认值

    Context.Provider
    • 每个 Context 对象都会返回一个 Provider React 组件,它允许消费组件订阅 context 的变化
    • Provider 接收一个 value 属性,传递给消费组件
    • 一个 Provider 可以和多个消费组件有对应关系
    • 多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据
    • 当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染

    创建context
    1. import React from "react";
    2. const ThemeContext = React.createContext({nickname: 'curry', work: '前端'})
    3. export default ThemeContext
    1. import React from "react";
    2. const UserContext = React.createContext()
    3. export default UserContext
     提供值
    1. import React, { Component } from 'react'
    2. import ThemeContext from './context/theme-context'
    3. import UserContext from './context/user-context'
    4. import Home from './context/Home'
    5. import Profile from './context/Profile'
    6. export class AppHome extends Component {
    7. render() {
    8. return (
    9. <div>
    10. App
    11. <UserContext.Provider value={{name: 'hgf', age: 23}}>
    12. <ThemeContext.Provider value={{color: 'red', size: '30px'}}>
    13. <Home />
    14. ThemeContext.Provider>
    15. UserContext.Provider>
    16. <Profile />
    17. div>
    18. )
    19. }
    20. }
    21. export default AppHome
    获取和使用方式 
    1. import React, { Component } from 'react'
    2. import ThemeContext from './theme-context'
    3. export class Profile extends Component {
    4. render() {
    5. console.log(this.context);
    6. return (
    7. <div>Profilediv>
    8. )
    9. }
    10. }
    11. Profile.contextType = ThemeContext
    12. export default Profile
    1. import React, { Component } from 'react'
    2. import ThemeContext from './theme-context';
    3. import UserContext from './user-context';
    4. export class HomeInfo extends Component {
    5. render() {
    6. console.log(this.context);
    7. return (
    8. <div>
    9. HomeInfo
    10. <UserContext.Consumer>
    11. {
    12. value => {
    13. return <h2>InfoUser: {value.age}h2>
    14. }
    15. }
    16. UserContext.Consumer>
    17. div>
    18. )
    19. }
    20. }
    21. HomeInfo.contextType = ThemeContext
    22. export default HomeInfo
  • 相关阅读:
    ECCV 2022 | 悉尼大学提出:绝对尺度感知,鲁棒,以及可泛化的自监督单目深度估计网络DynaDepth
    echarts饼图label显示不全原因?
    spring概述
    基于 CC2530 的多功能 ZigBee 继电器、开关、传感器和路由器的详细实现与JavaScript编码
    vcruntime140_1.dll 无法继续执行代码的修复方法分享
    怒刷LeetCode的第28天(Java版)
    【Vue.js生命周期】什么是生命周期?声明周期详解
    手把手实现 CSS 加载动画(一)
    7.MMD 法线贴图的设置与调教
    基于战争策略优化算法的函数寻优算法
  • 原文地址:https://blog.csdn.net/weixin_47342624/article/details/133176567