日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無(wú)先后,達(dá)者為師

網(wǎng)站首頁(yè) 編程語(yǔ)言 正文

React之組件的分類、使用,事件對(duì)象,this指向問(wèn)題,修改狀態(tài)以及受控組件與非受控組件

作者:Gik99 更新時(shí)間: 2023-08-01 編程語(yǔ)言

React之組件的介紹、創(chuàng)建與使用,事件對(duì)象,this指向問(wèn)題,修改狀態(tài)以及受控組件與非受控組件

  • 一、組件基本介紹
  • 二、組件創(chuàng)建
    • 2.1 函數(shù)組件
    • 2.2 類組件
  • 三、將組件提取到單獨(dú)的js文件中
  • 四、有狀態(tài)組件和無(wú)狀態(tài)組件
  • 五、類組件的狀態(tài)
  • 六、事件處理
    • 6.1 注冊(cè)事件
    • 6.2 事件對(duì)象
    • 6.3 this指向問(wèn)題
    • 6.4 this指向解決方案
  • 七、setState 修改狀態(tài)
  • 八、react核心理念(狀態(tài)不可變)
  • 九、表單處理
    • 9.1 受控組件
    • 9.2 非受控組件-ref

一、組件基本介紹

  • 組件是 React 開發(fā)(現(xiàn)代前端開發(fā))中最重要的內(nèi)容
  • 組件允許你將 UI 拆分為獨(dú)立、可復(fù)用的部分,每個(gè)部分都可以獨(dú)立的思考
  • 組合多個(gè)組件(組裝樂(lè)高積木)實(shí)現(xiàn)完整的頁(yè)面功能
  • 特點(diǎn):獨(dú)立、可復(fù)用、可組合
  • 組件包含三部分:HTML/CSS/JS
  • 展示頁(yè)面中的可復(fù)用部分

二、組件創(chuàng)建

2.1 函數(shù)組件

  • 函數(shù)組件:使用JS的函數(shù)或者箭頭函數(shù)創(chuàng)建的組件
    • 使用 JS 的函數(shù)(或箭頭函數(shù))創(chuàng)建的組件,叫做函數(shù)組件
    • 約定1:函數(shù)名稱必須以大寫字母開頭,React 據(jù)此區(qū)分組件和普通的 HTML標(biāo)簽
    • 約定2:函數(shù)組件必須有返回值,表示該組件的 UI 結(jié)構(gòu);如果不需要渲染任何內(nèi)容,則返回 null
  • 使用函數(shù)創(chuàng)建組件
// 使用普通函數(shù)創(chuàng)建組件:
function Hello() {
  return <div>這是我的第一個(gè)函數(shù)組件!</div>
}
function Button() {
  return <button>按鈕</button>
}

// 使用箭頭函數(shù)創(chuàng)建組件:
const Hello = () => <div>這是我的第一個(gè)函數(shù)組件!</div>
  • 使用組件
    • 組件就像 HTML 標(biāo)簽一樣可以被渲染到頁(yè)面中。組件表示的是一段結(jié)構(gòu)內(nèi)容,對(duì)于函數(shù)組件來(lái)說(shuō),渲染的內(nèi)容是函數(shù)返回值對(duì)應(yīng)的內(nèi)容
    • 使用函數(shù)名稱作為組件標(biāo)簽名稱
// 使用 雙標(biāo)簽 渲染組件:
<Hello></Hello>
ReactDOM.render(<Hello></Hello>, root)

// 使用 單標(biāo)簽 渲染組件:
<Hello />
ReactDOM.createRoot(document.querySelector('#root')).render(<Hello></Hello>)

小結(jié)

  1. 在react中可以使用函數(shù)或者箭頭函數(shù)創(chuàng)建組件
  2. 組件的首字母必須大寫

2.2 類組件

內(nèi)容

  • 使用 ES6 的 class 創(chuàng)建的組件,叫做類(class)組件
  • 約定1:類名稱也必須以大寫字母開頭
  • 約定2:類組件應(yīng)該繼承 React.Component 父類,從而使用父類中提供的方法或?qū)傩?/li>
  • 約定3:類組件必須提供 render 方法
  • 約定4:render 方法必須有返回值,表示該組件的 UI 結(jié)構(gòu)

定義組件

// 導(dǎo)入 React
import React from 'react'
class Hello extends React.Component {
  render() {
    return <div>Hello Class Component!</div> 
  }
}
ReactDOM.render(<Hello />, root)

// 只導(dǎo)入 Component
import { Component } from 'react'
class Hello extends Component {
  render() {
    return <div>Hello Class Component!</div> 
  }
}

使用組件

ReactDOM.createRoot(document.querySelector('#root')).render(<Hello></Hello>)

總結(jié)

  1. 使用class語(yǔ)法創(chuàng)建組件比函數(shù)創(chuàng)建稍微麻煩一些,但是類組件的功能會(huì)比函數(shù)組件的功能更加強(qiáng)大(hooks 之前

三、將組件提取到單獨(dú)的js文件中

實(shí)現(xiàn)方式

  1. 創(chuàng)建 Hello.js
  2. 創(chuàng)建組件(函數(shù) 或 類)
  3. 在 Hello.js 中導(dǎo)出該組件
  4. 在 index.js 中導(dǎo)入 Hello 組件
  5. 渲染組件

核心代碼

// index.js
//直接導(dǎo)入
import Hello from './Hello'

//按需導(dǎo)入
// import {Hello} from './Hello'

// 渲染導(dǎo)入的Hello組件
ReactDOM.createRoot(document.querySelector('#root')).render(<Hello></Hello>)


// Hello.js
import { Component } from 'react'
class Hello extends Component {
  render() {
    return <div>Hello Class Component!</div>
  }
}
// 導(dǎo)出Hello組件(默認(rèn)導(dǎo)出)
export default Hello

//按需導(dǎo)出
// export {
//	Hello
// }

四、有狀態(tài)組件和無(wú)狀態(tài)組件

內(nèi)容

  • 函數(shù)組件又叫做無(wú)狀態(tài)組件 函數(shù)組件是不能自己提供數(shù)據(jù)【前提:不考慮 hooks 的情況下】
  • 類組件又叫做有狀態(tài)組件 類組件可以自己提供數(shù)據(jù)
  • 狀態(tài)state是組件的私有數(shù)據(jù),當(dāng)組件的狀態(tài)發(fā)生了改變,頁(yè)面結(jié)構(gòu)也就發(fā)生了改變(數(shù)據(jù)驅(qū)動(dòng)視圖
  • 函數(shù)組件是沒(méi)有狀態(tài)的,只負(fù)責(zé)頁(yè)面的展示態(tài),不會(huì)發(fā)生變化),性能比較高
  • 類組件有自己的狀態(tài),負(fù)責(zé)更新UI,只要類組件的數(shù)據(jù)發(fā)生了改變,UI 就會(huì)發(fā)生更新動(dòng)態(tài))
  • 在項(xiàng)目中,一般都是由函數(shù)組件和類組件共同配合來(lái)完成的

比如計(jì)數(shù)器案例,點(diǎn)擊按鈕讓數(shù)值+1, 0和1就是不同時(shí)刻的狀態(tài),當(dāng)狀態(tài)從0變成1之后,UI也要跟著發(fā)生變化。React想要實(shí)現(xiàn)這種功能,就需要使用有狀態(tài)組件來(lái)完成。

  • 函數(shù)組件和類組件的區(qū)別:有沒(méi)有狀態(tài)【前提:不考慮 hooks 的情況下】

五、類組件的狀態(tài)

內(nèi)容

  • 狀態(tài)state,即數(shù)據(jù),是組件內(nèi)部的私有數(shù)據(jù),只能在組件內(nèi)部使用
  • 狀態(tài) state 的值是對(duì)象,表示一個(gè)組件中可以有多個(gè)數(shù)據(jù)
  • 通過(guò) this.state.xxx 來(lái)獲取狀態(tài)

核心代碼

  • 創(chuàng)建 state
class Hello extends Component {
  // 為組件提供狀態(tài)
  state = {
    count: 0,
    list: [],
    isLoading: true
  }

  render() {
    return (
      <div>計(jì)數(shù)器</div>
    )
  }
}
  • 讀取狀態(tài):通過(guò) this.state 來(lái)獲取狀態(tài)
class Hello extends Component {
  // ...
  render() {
    // 通過(guò) this.state 來(lái)訪問(wèn)類組件的狀態(tài)
    return (
      <div>計(jì)數(shù)器:{this.state.count}</div>
    )
  }
}

六、事件處理

6.1 注冊(cè)事件

內(nèi)容

  • React注冊(cè)事件與DOM的事件語(yǔ)法非常像

  • 語(yǔ)法on+事件名 ={事件處理程序} 比如onClick={this.handleClick}

  • 注意:React事件采用駝峰命名法,比如onMouseEnter, onClick

核心代碼

class App extends React.Component {
  handleClick() {
    console.log('點(diǎn)擊事件觸發(fā)')
  }
  
  render() {
    return (
      <div>
        <button onClick={this.handleClick}>點(diǎn)我</button>
      </div>
    )
  }
}

6.2 事件對(duì)象

核心代碼

  • 可以通過(guò)事件處理程序的參數(shù)獲取到事件對(duì)象
  • 注意:React 中的事件對(duì)象是 React 內(nèi)部處理后的事件對(duì)象,一般稱為:SyntheticBaseEvent 合成事件對(duì)象。用法與 DOM 原生的事件對(duì)象用法基本一致
function handleClick(e) {
  e.preventDefault()
  console.log('事件對(duì)象', e)
}

<a onClick={this.handleClick}>點(diǎn)我,不會(huì)跳轉(zhuǎn)頁(yè)面</a>

6.3 this指向問(wèn)題

內(nèi)容:

  • 事件處理程序中的this指向的是undefined

  • render方法中的this指向的是當(dāng)前react組件。只有事件處理程序中的this有問(wèn)題

  • 原因

    • 事件處理程序的函數(shù)式函數(shù)調(diào)用模式,在嚴(yán)格模式下,this指向undefined
    • render函數(shù)是被組件實(shí)例調(diào)用的,因此render函數(shù)中的this指向當(dāng)前組件
class App extends React.Component {
  state = {
    msg: 'hello react'
  }
  handleClick() {
    console.log(this.state.msg)
  }
  render() {
    return (
      <div>
        <button onClick={this.handleClick}>點(diǎn)我</button>
      </div>
    )
  }
}

總結(jié)

  1. 在react的事件處理函數(shù)中,this指向undefined

6.4 this指向解決方案

內(nèi)容

  • 解決事件處理程序中this指向問(wèn)題主要有三種方式

  • 方式1:箭頭函數(shù)

class App extends React.Component {
  state = {
    msg: 'hello react'
  }
  handleClick() {
    console.log(this.state.msg)
  }
  render() {
    return (
      <div>
        <button onClick={() => this.handleClick()}>點(diǎn)我</button>
      </div>
    )
  }
}
  • 方式2:bind
class App extends React.Component {
  state = {
    msg: 'hello react'
  }
  handleClick() {
    console.log(this.state.msg)
  }
  render() {
    return (
      <div>
        <button onClick={this.handleClick.bind(this)}>點(diǎn)我</button>
      </div>
    )
  }
}
  • 方式3:箭頭函數(shù)形式的實(shí)例方法 - 推薦使用
class App extends React.Component {
  state = {
    msg: 'hello react'
  }

  handleClick = () => {
    console.log(this.state.msg)
  }
  render() {
    return (
      <div>
        <button onClick={this.handleClick}>點(diǎn)我</button>
      </div>
    )
  }
}

總結(jié)

  1. 推薦使用方式3,箭頭函數(shù)形式的實(shí)例方法
  • 解釋為什么方式3可以解決 this 指向問(wèn)題:
// ES6
class Person1 {
  // 類的 構(gòu)造函數(shù)
  constructor() {
    // 構(gòu)造函數(shù)中的 this 就是實(shí)例對(duì)象
    console.log(this)
    this.name = 'jack'
    this.fn = () => {
      console.log(this)
    }
  }

  // 上述寫法簡(jiǎn)化語(yǔ)法:
  // name = 'jack'
  // fn = () => {}

  // 這個(gè)形式的方法會(huì)被添加到原型中
  sayHi() {}
}

說(shuō)明:

fn = () => {}  這種形式的語(yǔ)法是簡(jiǎn)化語(yǔ)法(語(yǔ)法糖),書寫會(huì)更簡(jiǎn)單。實(shí)際上,完整的寫法是:

constructor() {
  this.fn = () => {}
}

即:在構(gòu)造函數(shù)中,給 this 添加了一個(gè)方法 fn

為什么可以解決 this 指向問(wèn)題呢?
因?yàn)?constructor 中創(chuàng)建的箭頭函數(shù),內(nèi)部的 this 會(huì)指向 constructor 中的 this
而 constructor 中的 this 就是實(shí)例對(duì)象(也就是我們需要的 this

七、setState 修改狀態(tài)

內(nèi)容

  • 語(yǔ)法:this.setState({ 要修改的部分?jǐn)?shù)據(jù) })
  • setState() 作用:1 修改 state 2 更新 UI
  • 思想:數(shù)據(jù)驅(qū)動(dòng)視圖,也就是只需要修改數(shù)據(jù)(狀態(tài))那么頁(yè)面(視圖)就會(huì)自動(dòng)刷新
    • 核心:數(shù)據(jù)!!!
    • 從現(xiàn)在開始,我們關(guān)心的是如何修改數(shù)據(jù),而不再是關(guān)心如何修改DOM
    • 并且,注意:盡量避免直接手動(dòng) DOM(通過(guò) document.querySelector() 獲取到到DOM對(duì)象然后再操作) 操作!!!
  • 注意:不要直接修改 state 中的值,這是無(wú)效的

核心代碼

class Hello extends Component {
  state = {
    count: 0
  }

	handleClick = () => {
    this.setState({
      count: 10
    })
  }  

  render() {
    return (
      <div>
        <h1>計(jì)數(shù)器:{this.state.count}</h1>
        <button onClick={this.handleClick}>+1</button>
      </div>
    )
  }
}

// 在 count 當(dāng)前值的基礎(chǔ)上加 1
this.setState({
  count: this.state.count + 10
})

總結(jié)

  1. 能直接修改 state 的值嗎?不能
  2. 如何修改 React 組件中的狀態(tài)?setState()
  3. setState 是哪來(lái)的?從 Component 父類繼承過(guò)來(lái)的

八、react核心理念(狀態(tài)不可變)

內(nèi)容:

  • 狀態(tài)不可變指的是:不要直接修改狀態(tài)的值,而是基于當(dāng)前狀態(tài)創(chuàng)建新的狀態(tài)值

核心代碼

state = {
  count: 0,
  list: [1, 2, 3],
  person: {
    name: 'jack',
    age: 18
  }
}

// 【不推薦】直接修改當(dāng)前值的操作:
this.state.count++
++this.state.count
this.state.count += 1
this.state.count = 1

// 只要是數(shù)組中直接修改當(dāng)前數(shù)組的方法都不能用!
this.state.list.push(123)

this.state.person.name = 'rose'

// 【推薦】不是直接修改當(dāng)前值,而是創(chuàng)建新值的操作:
this.setState({
  count: this.state.count + 1,
  list: [...this.state.list, 123],
  person: {
    ...this.state.person,
    // 要修改的屬性,會(huì)覆蓋原來(lái)的屬性,這樣,就可以達(dá)到修改對(duì)象中屬性的目的了
    name: 'rose'
  }
})

九、表單處理

9.1 受控組件

內(nèi)容

  • HTML中表單元素是可輸入的,即表單元素維護(hù)著自己的可變狀態(tài)(value)
  • 但是在react中,可變狀態(tài)通常是保存在state中的,并且要求狀態(tài)只能通過(guò)setState進(jìn)行修改
  • React中將state中的數(shù)據(jù)與表單元素的value值綁定到了一起,由state的值來(lái)控制表單元素的值
  • 受控組件:value值受到了react狀態(tài)控制的表單元素

核心代碼:

class App extends React.Component {
  state = {
    msg: 'hello react'
  }

  handleChange = (e) => {
    this.setState({
      msg: e.target.value
    })
  }

  render() {
    return (
      <div>
        <input type="text" value={this.state.msg} onChange={this.handleChange}/>
      </div>
    )
  }
}

總結(jié)

  1. 使用受控組件的方式處理表單元素后,狀態(tài)的值就是表單元素的值。即:想要操作表單元素的值,只需要操作對(duì)應(yīng)的狀態(tài)即可*

9.2 非受控組件-ref

非受控組件借助于ref,使用原生DOM的方式來(lái)獲取表單元素的值
內(nèi)容

  • 受控組件是通過(guò) React 組件的狀態(tài)來(lái)控制表單元素的值
  • 非受控組件是通過(guò)手動(dòng)操作 DOM 的方式來(lái)控制
  • 此時(shí),需要用到一個(gè)新的概念:ref
  • ref:用來(lái)在 React 中獲取 DOM 元素

核心代碼

// 1 導(dǎo)入 createRef 函數(shù)( 用來(lái)創(chuàng)建 ref 對(duì)象 )
import { createRef } from 'react'

class Hello extends Component {
  // 2 調(diào)用 createRef 函數(shù)來(lái)創(chuàng)建一個(gè) ref 對(duì)象
  //   ref 對(duì)象的名稱(txtRef)可以是任意值
  //   命名要規(guī)范: txt(DOM 元素的自己標(biāo)識(shí)) + Ref
  txtRef = createRef()

  handleClick = () => {
    // 文本框?qū)?yīng)的 DOM 元素
    // console.log(this.txtRef.current)

    // 4 獲取文本框的值:
    console.log(this.txtRef.current.value)
  }

  render() {
    return (
      <div>
        {/*
        	3 將創(chuàng)建好的 ref 對(duì)象,設(shè)置為 input 標(biāo)簽的 ref 屬性值
        		作用:將 ref 和 input DOM 綁定到一起,將來(lái)在通過(guò) this.txtRef 拿到的就是當(dāng)前 DOM 對(duì)象
        */}
        <input ref={this.txtRef} />
        <button onClick={this.handleClick}>獲取文本框的值</button>
      </div>
    )
  }
}

原文鏈接:https://blog.csdn.net/Gik99/article/details/131870685

  • 上一篇:沒(méi)有了
  • 下一篇:沒(méi)有了
欄目分類
最近更新