網站首頁 編程語言 正文
React之組件的介紹、創建與使用,事件對象,this指向問題,修改狀態以及受控組件與非受控組件
- 一、組件基本介紹
- 二、組件創建
- 2.1 函數組件
- 2.2 類組件
- 三、將組件提取到單獨的js文件中
- 四、有狀態組件和無狀態組件
- 五、類組件的狀態
- 六、事件處理
- 6.1 注冊事件
- 6.2 事件對象
- 6.3 this指向問題
- 6.4 this指向解決方案
- 七、setState 修改狀態
- 八、react核心理念(狀態不可變)
- 九、表單處理
- 9.1 受控組件
- 9.2 非受控組件-ref
一、組件基本介紹
- 組件是 React 開發(現代前端開發)中最重要的內容
- 組件允許你將 UI 拆分為獨立、可復用的部分,每個部分都可以獨立的思考
- 組合多個組件(組裝樂高積木)實現完整的頁面功能
- 特點:獨立、可復用、可組合
- 組件包含三部分:HTML/CSS/JS
- 展示頁面中的可復用部分
二、組件創建
2.1 函數組件
- 函數組件:使用JS的函數或者箭頭函數創建的組件
- 使用 JS 的函數(或箭頭函數)創建的組件,叫做
函數組件
- 約定1:函數名稱必須以大寫字母開頭,React 據此區分組件和普通的 HTML標簽
- 約定2:函數組件必須有返回值,表示該組件的 UI 結構;如果不需要渲染任何內容,則返回
null
- 使用 JS 的函數(或箭頭函數)創建的組件,叫做
- 使用函數創建組件
// 使用普通函數創建組件:
function Hello() {
return <div>這是我的第一個函數組件!</div>
}
function Button() {
return <button>按鈕</button>
}
// 使用箭頭函數創建組件:
const Hello = () => <div>這是我的第一個函數組件!</div>
- 使用組件
- 組件就像 HTML 標簽一樣可以被渲染到頁面中。組件表示的是一段結構內容,對于函數組件來說,渲染的內容是函數返回值對應的內容
- 使用函數名稱作為組件標簽名稱
// 使用 雙標簽 渲染組件:
<Hello></Hello>
ReactDOM.render(<Hello></Hello>, root)
// 使用 單標簽 渲染組件:
<Hello />
ReactDOM.createRoot(document.querySelector('#root')).render(<Hello></Hello>)
小結:
- 在react中可以使用函數或者箭頭函數創建組件
- 組件的首字母必須大寫
2.2 類組件
內容
- 使用 ES6 的 class 創建的組件,叫做類(class)組件
- 約定1:類名稱也必須以大寫字母開頭
- 約定2:類組件應該繼承 React.Component 父類,從而使用父類中提供的方法或屬性
- 約定3:類組件必須提供 render 方法
- 約定4:render 方法必須有返回值,表示該組件的 UI 結構
定義組件
// 導入 React
import React from 'react'
class Hello extends React.Component {
render() {
return <div>Hello Class Component!</div>
}
}
ReactDOM.render(<Hello />, root)
// 只導入 Component
import { Component } from 'react'
class Hello extends Component {
render() {
return <div>Hello Class Component!</div>
}
}
使用組件
ReactDOM.createRoot(document.querySelector('#root')).render(<Hello></Hello>)
總結
- 使用class語法創建組件比函數創建稍微麻煩一些,但是類組件的功能會比函數組件的功能更加強大(hooks 之前)
三、將組件提取到單獨的js文件中
實現方式
- 創建 Hello.js
- 創建組件(函數 或 類)
- 在 Hello.js 中導出該組件
- 在 index.js 中導入 Hello 組件
- 渲染組件
核心代碼
// index.js
//直接導入
import Hello from './Hello'
//按需導入
// import {Hello} from './Hello'
// 渲染導入的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>
}
}
// 導出Hello組件(默認導出)
export default Hello
//按需導出
// export {
// Hello
// }
四、有狀態組件和無狀態組件
內容:
- 函數組件又叫做無狀態組件 函數組件是不能自己提供數據【前提:不考慮 hooks 的情況下】
- 類組件又叫做有狀態組件 類組件可以自己提供數據
- 狀態state是組件的私有數據,當組件的狀態發生了改變,頁面結構也就發生了改變(數據驅動視圖)
-
函數組件是沒有狀態的,只負責頁面的展示(
靜
態,不會發生變化),性能比較高 -
類組件有自己的狀態,負責更新UI,只要類組件的數據發生了改變,UI 就會發生更新(
動
態) - 在項目中,一般都是由函數組件和類組件共同配合來完成的
比如計數器案例,點擊按鈕讓數值+1, 0和1就是不同時刻的狀態,當狀態從0變成1之后,UI也要跟著發生變化。React想要實現這種功能,就需要使用有狀態組件來完成。
- 函數組件和類組件的區別:有沒有狀態【前提:不考慮 hooks 的情況下】
五、類組件的狀態
內容:
- 狀態
state
,即數據,是組件內部的私有數據,只能在組件內部使用 - 狀態 state 的值是對象,表示一個組件中可以有多個數據
- 通過
this.state.xxx
來獲取狀態
核心代碼
- 創建 state
class Hello extends Component {
// 為組件提供狀態
state = {
count: 0,
list: [],
isLoading: true
}
render() {
return (
<div>計數器</div>
)
}
}
- 讀取狀態:通過
this.state
來獲取狀態
class Hello extends Component {
// ...
render() {
// 通過 this.state 來訪問類組件的狀態
return (
<div>計數器:{this.state.count}</div>
)
}
}
六、事件處理
6.1 注冊事件
內容:
-
React注冊事件與DOM的事件語法非常像
-
語法
on+事件名 ={事件處理程序}
比如onClick={this.handleClick}
-
注意:React事件采用駝峰命名法,比如
onMouseEnter
,onClick
核心代碼
class App extends React.Component {
handleClick() {
console.log('點擊事件觸發')
}
render() {
return (
<div>
<button onClick={this.handleClick}>點我</button>
</div>
)
}
}
6.2 事件對象
核心代碼
- 可以通過事件處理程序的參數獲取到事件對象
- 注意:React 中的事件對象是 React 內部處理后的事件對象,一般稱為:SyntheticBaseEvent 合成事件對象。用法與 DOM 原生的事件對象用法基本一致
function handleClick(e) {
e.preventDefault()
console.log('事件對象', e)
}
<a onClick={this.handleClick}>點我,不會跳轉頁面</a>
6.3 this指向問題
內容:
-
事件處理程序中的this指向的是
undefined
-
render方法中的this指向的是當前react組件。只有事件處理程序中的this有問題
-
原因
- 事件處理程序的函數式函數調用模式,在嚴格模式下,this指向
undefined
- render函數是被組件實例調用的,因此render函數中的this指向當前組件
- 事件處理程序的函數式函數調用模式,在嚴格模式下,this指向
class App extends React.Component {
state = {
msg: 'hello react'
}
handleClick() {
console.log(this.state.msg)
}
render() {
return (
<div>
<button onClick={this.handleClick}>點我</button>
</div>
)
}
}
總結:
- 在react的事件處理函數中,this指向
undefined
6.4 this指向解決方案
內容:
-
解決事件處理程序中this指向問題主要有三種方式
-
方式1:箭頭函數
class App extends React.Component {
state = {
msg: 'hello react'
}
handleClick() {
console.log(this.state.msg)
}
render() {
return (
<div>
<button onClick={() => this.handleClick()}>點我</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)}>點我</button>
</div>
)
}
}
- 方式3:箭頭函數形式的實例方法 - 推薦使用
class App extends React.Component {
state = {
msg: 'hello react'
}
handleClick = () => {
console.log(this.state.msg)
}
render() {
return (
<div>
<button onClick={this.handleClick}>點我</button>
</div>
)
}
}
總結
- 推薦使用方式3,箭頭函數形式的實例方法
- 解釋為什么方式3可以解決 this 指向問題:
// ES6
class Person1 {
// 類的 構造函數
constructor() {
// 構造函數中的 this 就是實例對象
console.log(this)
this.name = 'jack'
this.fn = () => {
console.log(this)
}
}
// 上述寫法簡化語法:
// name = 'jack'
// fn = () => {}
// 這個形式的方法會被添加到原型中
sayHi() {}
}
說明:
fn = () => {} 這種形式的語法是簡化語法(語法糖),書寫會更簡單。實際上,完整的寫法是:
constructor() {
this.fn = () => {}
}
即:在構造函數中,給 this 添加了一個方法 fn
為什么可以解決 this 指向問題呢?
因為 constructor 中創建的箭頭函數,內部的 this 會指向 constructor 中的 this
而 constructor 中的 this 就是實例對象(也就是我們需要的 this)
七、setState 修改狀態
內容:
- 語法:
this.setState({ 要修改的部分數據 })
- setState() 作用:1 修改 state 2 更新 UI
- 思想:數據驅動視圖,也就是只需要修改數據(狀態)那么頁面(視圖)就會自動刷新
- 核心:數據?。。?/li>
- 從現在開始,我們關心的是如何修改數據,而不再是關心如何修改DOM
- 并且,注意:盡量避免直接手動 DOM(通過 document.querySelector() 獲取到到DOM對象然后再操作) 操作?。。?/li>
- 注意:不要直接修改 state 中的值,這是無效的!
核心代碼
class Hello extends Component {
state = {
count: 0
}
handleClick = () => {
this.setState({
count: 10
})
}
render() {
return (
<div>
<h1>計數器:{this.state.count}</h1>
<button onClick={this.handleClick}>+1</button>
</div>
)
}
}
// 在 count 當前值的基礎上加 1
this.setState({
count: this.state.count + 10
})
總結:
- 能直接修改 state 的值嗎?不能
- 如何修改 React 組件中的狀態?
setState()
- setState 是哪來的?從 Component 父類繼承過來的
八、react核心理念(狀態不可變)
內容:
- 狀態不可變指的是:不要直接修改狀態的值,而是基于當前狀態創建新的狀態值
核心代碼:
state = {
count: 0,
list: [1, 2, 3],
person: {
name: 'jack',
age: 18
}
}
// 【不推薦】直接修改當前值的操作:
this.state.count++
++this.state.count
this.state.count += 1
this.state.count = 1
// 只要是數組中直接修改當前數組的方法都不能用!
this.state.list.push(123)
this.state.person.name = 'rose'
// 【推薦】不是直接修改當前值,而是創建新值的操作:
this.setState({
count: this.state.count + 1,
list: [...this.state.list, 123],
person: {
...this.state.person,
// 要修改的屬性,會覆蓋原來的屬性,這樣,就可以達到修改對象中屬性的目的了
name: 'rose'
}
})
九、表單處理
9.1 受控組件
內容:
- HTML中表單元素是可輸入的,即表單元素維護著自己的可變狀態(value)
- 但是在react中,可變狀態通常是保存在
state
中的,并且要求狀態只能通過setState
進行修改 - React中將state中的數據與表單元素的value值綁定到了一起,由state的值來控制表單元素的值
- 受控組件:value值受到了react狀態控制的表單元素
核心代碼:
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>
)
}
}
總結:
- 使用受控組件的方式處理表單元素后,狀態的值就是表單元素的值。即:想要操作表單元素的值,只需要操作對應的狀態即可*
9.2 非受控組件-ref
非受控組件借助于ref,使用原生DOM的方式來獲取表單元素的值
內容
- 受控組件是通過 React 組件的狀態來控制表單元素的值
- 非受控組件是通過手動操作 DOM 的方式來控制
- 此時,需要用到一個新的概念:
ref
- ref:用來在 React 中獲取 DOM 元素
核心代碼
// 1 導入 createRef 函數( 用來創建 ref 對象 )
import { createRef } from 'react'
class Hello extends Component {
// 2 調用 createRef 函數來創建一個 ref 對象
// ref 對象的名稱(txtRef)可以是任意值
// 命名要規范: txt(DOM 元素的自己標識) + Ref
txtRef = createRef()
handleClick = () => {
// 文本框對應的 DOM 元素
// console.log(this.txtRef.current)
// 4 獲取文本框的值:
console.log(this.txtRef.current.value)
}
render() {
return (
<div>
{/*
3 將創建好的 ref 對象,設置為 input 標簽的 ref 屬性值
作用:將 ref 和 input DOM 綁定到一起,將來在通過 this.txtRef 拿到的就是當前 DOM 對象
*/}
<input ref={this.txtRef} />
<button onClick={this.handleClick}>獲取文本框的值</button>
</div>
)
}
}
原文鏈接:https://blog.csdn.net/Gik99/article/details/131870685
- 上一篇:沒有了
- 下一篇:沒有了
相關推薦
- 2023-07-05 React hooks之useCallback的使用與性能分析
- 2022-04-03 Rust?連接?PostgreSQL?數據庫的詳細過程_PostgreSQL
- 2022-09-06 Golang實現http重定向https_Golang
- 2022-07-10 JDK13版本的環境變量的配置
- 2022-12-19 QT實現自定義Http客戶端的示例代碼_C 語言
- 2022-03-31 Python的三個重要函數詳解_python
- 2022-07-22 Mybatis為實體類自定義別名的兩種方式
- 2022-06-29 基于C++實現五子棋小游戲_C 語言
- 欄目分類
-
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支