網(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
- 使用 JS 的函數(shù)(或箭頭函數(shù))創(chuàng)建的組件,叫做
- 使用函數(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é):
- 在react中可以使用函數(shù)或者箭頭函數(shù)創(chuàng)建組件
- 組件的首字母必須大寫
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é)
- 使用class語(yǔ)法創(chuàng)建組件比函數(shù)創(chuàng)建稍微麻煩一些,但是類組件的功能會(huì)比函數(shù)組件的功能更加強(qiáng)大(hooks 之前)
三、將組件提取到單獨(dú)的js文件中
實(shí)現(xiàn)方式
- 創(chuàng)建 Hello.js
- 創(chuàng)建組件(函數(shù) 或 類)
- 在 Hello.js 中導(dǎo)出該組件
- 在 index.js 中導(dǎo)入 Hello 組件
- 渲染組件
核心代碼
// 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)前組件
- 事件處理程序的函數(shù)式函數(shù)調(diào)用模式,在嚴(yán)格模式下,this指向
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é):
- 在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é)
- 推薦使用方式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é):
- 能直接修改 state 的值嗎?不能
- 如何修改 React 組件中的狀態(tài)?
setState()
- 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é):
- 使用受控組件的方式處理表單元素后,狀態(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)有了
相關(guān)推薦
- 2022-05-15 c++11?實(shí)現(xiàn)枚舉值到枚舉名的轉(zhuǎn)換問(wèn)題_C 語(yǔ)言
- 2023-01-08 利用Qt實(shí)現(xiàn)獲取計(jì)算機(jī)的硬件信息_C 語(yǔ)言
- 2023-05-06 Python中dilb和face_recognition第三方包安裝失敗的解決_python
- 2023-01-05 C#不提升自己程序的權(quán)限實(shí)現(xiàn)操作注冊(cè)表_C#教程
- 2022-09-05 Involution: Inverting the Inherence of Convolution
- 2022-10-07 Unity游戲開發(fā)實(shí)現(xiàn)場(chǎng)景切換示例_C#教程
- 2022-05-29 Android?App如何防止抓包_Android
- 2022-10-30 移動(dòng)web開發(fā)技能之touch事件詳解_IOS
- 欄目分類
-
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支