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

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

二、组件的事件绑定

// 类组件引入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

三、组件事件传参

// 类组件引入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我爱你')}>
      {/* <a href='https://www.baidu.com'>百度</a> */}
      这是函数组件
    </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>
        {/* <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

// event 是React封装的, 可以看到  __proto__.constructor是SyntheticEvent, 模拟出来DOm事件所有能力
// event.nativeEvent是原生事件对象, 原生的打印出来是MouseEvent
// 和dom事件不一样,和vue也不一样
// React16绑定到document, React17事件绑定到root组件(有利于多个React版本并存,例如微前端)

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

在这里插入图片描述

四、组件状态

在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

五、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 <div onClick={this.clickHandler} style={{fontSize: '30px',color: 'red'}}>这是我第一个类组件</div>
//   }
// }

// 2.箭头函数写法

// class HelloComponent extends React.Component{
//   clickHandler () {
//     console.log(this)
//   }
//   render () {
//     // render函数的this已经被react做了修改
//     // 这里的this就是指向当前组件实例
//     console.log('父函数中的this指向为:', this)
//     // 通过箭头函数的写法 直接沿用父函数的this指向也ok
//     return <div onClick={() => this.clickHandler()} style={{fontSize: '30px',color: 'red'}}>这是我第一个类组件</div>
//   }
// }


// 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

六、受控表单组件

// 类组件引入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状态的最新值

七、非受控表单组件

// 类组件引入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拿到的就是文本框的值

八、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避免这个问题
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老电影故事

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值