• React组件


    一、React组件

    在这里插入图片描述

    1、函数组件

    • 纯函数,输入props,输出JSX
    • 没有实例(没有this),没有生命周期(不能扩展其他方法),没有state
    • 不能扩展其他方法
    // 函数组件
    // 组件的名称必须首字母大写
    // 函数组件必须有返回值 如果不需要渲染任何内容,则返回 null
    function HelloFn () {
      return <div>这是我的第一个函数组件!</div>
    }
    
    // 定义类组件
    function App () {
      return (
        <div className="App">
          {/* 渲染函数组件 */}
          <HelloFn />
          <HelloFn></HelloFn>
        </div>
      )
    }
    export default App
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2、类组件

    // 引入React
    import React from 'react'
    
    // 类组件
    // 使用 ES6 的 class 创建的组件,叫做类(class)组件
    // 类名称也必须以大写字母开头
    // 类组件应该继承 React.Component 父类,从而使用父类中提供的方法或属性
    // 类组件必须提供 render 方法render 方法必须有返回值,表示该组件的 UI 结构
    class HelloC extends React.Component {
      render () {
        return <div>这是我的第一个类组件!</div>
      }
    }
    
    function App () {
      return (
        <div className="App">
          {/* 渲染类组件 */}
          <HelloC />
          <HelloC></HelloC>
        </div>
      )
    }
    export default App
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    二、组件的事件绑定

    // 类组件引入React
    import React from 'react'
    
    // 函数组件
    // react事件采用驼峰命名法
    function Hello() {
      const clickHandler = (e) => { // 获取事件对象e只需要在 事件的回调函数中 补充一个形参e即可拿到
        console.log(e, 66666)
      }
      return <div onClick={clickHandler}>hello</div>
    }
    
    
    // 类组件
    class HelloComponent extends React.Component{
      // 事件回调函数 (标准写法 可以避免this指向问题) !!!!!!
      // 回调函数中的this指向是当前的组件实例对象
      clickHandler = () => {
        // 这里的this指向的是正确的当前的组件实例对象   推荐这么写!!!!!!
        console.log(this)
      }
      
      clickHandler1 () {
        // 这里的this 不指向当前的组件实例对象而指向undefined 存在this丢失问题
        console.log(this)
      }
      render () {
        return <div onClick={this.clickHandler} style={{fontSize: '30px',color: 'red'}}>这是我第一个类组件</div>
      }
    }
    
    function App () {
      return (
        <div className="App">
          <Hello/>
          <Hello></Hello>
          <HelloComponent/>
          <HelloComponent></HelloComponent>
        </div>
      )
    }
    
    export default App
    
    • 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

    三、组件事件传参

    // 类组件引入React
    import React from 'react'
    
    // 函数组件
    // 传递自定义参数
    function Hello() {
      const clickHandler = (e, msg) => {
        // e.preventDefault() // 阻止事件的默认行为
        console.log(66666, e, msg)
      }
      return (
        <div onClick={(e) => clickHandler(e, 'mua我爱你')}>
          {/* 百度 */}
          这是函数组件
        </div>
      )
    }
    
    
    // 类组件
    class HelloComponent extends React.Component{
      // 事件回调函数 (标准写法 可以避免this指向问题)
      // 回调函数中的this指向是当前的组件实例对象
      clickHandler = (e, num) => {
        console.log(this, e, num)
      }
      render () {
        return (
          <>
            <button onClick={(e) => this.clickHandler(e, '123')}>click me</button>
            {/* 
    {fontSize: '30px',color: 'red'}}>这是我第一个类组件
    */
    } </> ) } } function App () { return ( <div className="App"> <Hello/> <Hello></Hello> <HelloComponent/> <HelloComponent></HelloComponent> </div> ) } export default App // event 是React封装的, 可以看到 __proto__.constructor是SyntheticEvent, 模拟出来DOm事件所有能力 // event.nativeEvent是原生事件对象, 原生的打印出来是MouseEvent // 和dom事件不一样,和vue也不一样 // React16绑定到document, React17事件绑定到root组件(有利于多个React版本并存,例如微前端)
    • 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

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    四、组件状态

    在React hook出来之前,函数式组件是没有自己的状态的,所以我们统一通过类组件来讲解

    不要直接修改state中的值,必须通过setState方法进行修改

    // 类组件引入React
    import React from 'react'
    
    // 组件状态
    // 不要直接修改state中的值,必须通过setState方法进行修改 
    class TestComponent extends React.Component{
      // 定义组件状态
      state = {
        name: 'zm',
        count: 0
      }
      setCount = () => {
        this.setState({
          count: this.state.count + 1,
          name: 'zzzz'
        })
      }
      render () {
        // 使用状态
        return (
          <div>
            this is TestComponent, name为: {this.state.name}, count: {this.state.count}
            <button onClick={this.setCount}>click++</button>
          </div>
        )
      }
    }
    
    function App () {
      return (
        <div className="App">
          <TestComponent/>
        </div>
      )
    }
    
    export default App
    
    • 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

    五、this指向问题

    在这里插入图片描述

    // 类组件引入React
    import React from 'react'
    
    // 类组件 this有问题的写法
    
    // 1.constructor中通过bind强行绑定this
    
    // class HelloComponent extends React.Component{
    //   constructor () {
    //     super()
    //     // 使用bind强行修改this指向
    //     // 相当于在类组件初始化的阶段,就可以把回调函数的this修改到
    //     // 永远指向当前组件的实例对象
    //     this.clickHandler = this.clickHandler.bind(this)
    //   }
    //   clickHandler () {
    //     console.log(this) // 如果没有上面的bind 打印就是undefined
    //   }
    //   render () {
    //     return 
    {fontSize: '30px',color: 'red'}}>这是我第一个类组件
    // } // } // 2.箭头函数写法 // class HelloComponent extends React.Component{ // clickHandler () { // console.log(this) // } // render () { // // render函数的this已经被react做了修改 // // 这里的this就是指向当前组件实例 // console.log('父函数中的this指向为:', this) // // 通过箭头函数的写法 直接沿用父函数的this指向也ok // return
    this.clickHandler()} style={{fontSize: '30px',color: 'red'}}>这是我第一个类组件
    // } // } // 3. class field写法 最推荐 !!!!!!!!!!!!!!!!!!!!! class HelloComponent extends React.Component{ clickHandler = () => { console.log(this) } render () { return <div onClick={this.clickHandler} style={{fontSize: '30px',color: 'red'}}>这是我第一个类组件</div> } } function App () { return ( <div className="App"> <HelloComponent/> </div> ) } export default App
    • 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

    六、受控表单组件

    // 类组件引入React
    import React from 'react'
    
    class InputComponent extends React.Component{
      state = {
        message: 'zm66666'
      }
      changeHandler = (e) => {
        this.setState({
          message: e.target.value
        })
      }
      render () {
        // 使用状态
        return (
          <div>
            {/* 绑定value 绑定事件 */}
            <input type='text' value={this.state.message} onChange={this.changeHandler} />
          </div>
        )
      }
    }
    
    function App () {
      return (
        <div className="App">
          <InputComponent/>
        </div>
      )
    }
    
    export default App
    
    
    // 受控组件:input框自己的状态被React组件状态控制
    
    // 1. 在组件的state中声明一个组件的状态数据
    // 2. 将状态数据设置为input标签元素的value属性的值
    // 3. 为input添加change事件,在事件处理程序中,通过事件对象e获取到当前文本框的值(即用户当前输入的值)
    // 4. 调用setState方法,将文本框的值作为state状态的最新值
    
    • 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

    七、非受控表单组件

    // 类组件引入React createRef
    import React, { createRef } from 'react'
    
    class InputComponent extends React.Component{
      // 使用createRef产生一个存放dom的对象容器
      msgRef = createRef()
    
      changeHandler = () => {
        console.log(this.msgRef.current)
        console.log(this.msgRef.current.value)
      }
    
      render () {
        // 使用状态
        return (
          <div>
            {/* ref绑定 获取真实dom */}
            <input ref={this.msgRef} />
            <button onClick={this.changeHandler}>click</button>
          </div>
        )
      }
    }
    
    function App () {
      return (
        <div className="App">
          <InputComponent/>
        </div>
      )
    }
    
    export default App
    
    
    // 非受控组件: 
    // 通过手动操作dom的方式获取文本框的值
    // 文本框的状态不受react组件的state中的状态控制
    // 直接通过原生dom获取输入框的值
    
    // 1.导入createRef 函数
    // 2.调用createRef函数,创建一个ref对象,存储到名为msgRef的实例属性中
    // 3.为input添加ref属性,值为msgRef
    // 4.在按钮的事件处理程序中,通过msgRef.current即可拿到input对应的dom元素,
    // 而其中msgRef.current.value拿到的就是文本框的值
    
    • 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

    八、dangerouslySetInnerHTML

    在这里插入图片描述

    九、immer

    import React, { FC, useState } from 'react'
    import { produce } from 'immer'
    
    const ImmerDemo: FC = () => {
    
      const [userInfo, setUserInfo] = useState({ name: 'zm', age: 25 })
      
      const changeAge = () => {
        // setUserInfo({ name: 'zm11', age: 666 }) // 不可变数据 不去修改state值 而是传入一个新的值
        setUserInfo(produce(draft => {
          draft.age = 999
        }))
      }
    
      return (
        <>
          <div>
            <h2>不可变数据</h2>
            <div>{JSON.stringify(userInfo)}</div>
            <button onClick={changeAge}>change age</button>
          </div>
        </>
      )
    }
    
    
    export default ImmerDemo
    
    
    // 使用immer
    // 1、state是不可变数据
    // 2、操作成本高,不稳定性
    // 3、使用immer避免这个问题
    
    • 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
  • 相关阅读:
    docker 构建并运行 python项目
    grid新建主从一对多
    从区划边界geojson中查询经纬度坐标对应的省市区县乡镇名称,开源Java工具,内存占用低、高性能
    男士证件照要不要西服领带?
    将文件名称中空格以左的部分全部删除重命名
    Java类的初始化过程
    程序员天天 CURD,怎么才能成长,职业发展的思考(2)
    深入Linux内核理解epoll事件轮询机制
    ModuleNotFoundError: No module named ‘sklearn.cross_validation‘
    请求二进制数据和base64格式数据的预览显示
  • 原文地址:https://blog.csdn.net/weixin_44582045/article/details/133671371