React 組件中的事件處理、組件(受控、非受控)、函數(shù)柯里化

2021-9-14    前端達(dá)人

事件處理

在React中獲取虛擬組件中的標(biāo)簽的值

  1. 使用組件的 refs屬性
  2. 在虛擬組件的標(biāo)簽中定義事件,在事件中通過 箭頭函數(shù) 獲取標(biāo)簽的值
  3. 使用事件對(duì)象——event

事件處理:

  • 通過onXxx屬性指定事件處理函數(shù)(注意大小寫)
    • React使用的是自定義(合成)事件, 而不是使用的原生DOM事件 ———為了更好的兼容性
    • React中的事件是通過事件委托方式處理的(委托給組件最外層的元素) ————為了高效
  • 通過event.target得到發(fā)生事件的DOM元素對(duì)象 ———不要過度使用ref

使用event.target屬性:

//創(chuàng)建組件 class Demo extends React.Component{ myRef = React.createRef() //展示輸入框的數(shù)據(jù) showData = (event)=>{ alert(event.target.value); } render(){ return( <div> <input onBlur={this.showData} type="text" placeholder="失去焦點(diǎn)提示數(shù)據(jù)"/> </div> ) } } //渲染組件到頁面 ReactDOM.render(<Demo/>,document.getElementById('test')) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

React事件處理和Dom事件處理區(qū)別:

1、在 語法 上的不同點(diǎn):

  • React事件名采用駝峰命名法,即事件名首字母大寫。如onclick(Dom)——onClick(React)

  • 響應(yīng)事件的函數(shù)在React中以 對(duì)象方式 賦值,Dom是以 字符串方式 賦值

    <button onclick= ' clickMe( ) '>提交</button> ——Dom方式 <button onClick={ clickMe( ) }>提交</button> ——React方式 
            
    • 1
    • 2

2、在阻止事件的默認(rèn)行為有區(qū)別:React事件是合成的,DOM事件是原生

  • Dom:返回false
  • React:顯示的調(diào)用事件對(duì)象event.preventDefault

React事件處理函數(shù)

  • 1、使用ES6的箭頭函數(shù)

    class MyComponent extends React.Component{ constructor(props){ super(props); this.state={ number:0 } handleClick=()=>{ ++this.state.number; console.log(this.state.number); } render(){ return( <div> <button type='button' onClick={this.handleClick}>點(diǎn)我</button> </div> ) } } ReactDOM.render(<MyComponent/>,document.getElementById('example')); 
            
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
  • 2、在組件中定義事件處理函數(shù)

    class MyComponent extends React.Component{ constructor(props){ super(props); this.state={ number:0 } this.handleClick=this.handleClick.bind(this); } handleClick(){ ++this.state.number; console.log(this.state.number); } render(){ return( <div> <button type='button' onClick={this.handleClick}>點(diǎn)我</button> </div> ) } } ReactDOM.render(<MyComponent/>,document.getElementById('example')); 
            
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 注:這種方法的好處是每次render渲染都不會(huì)重新創(chuàng)建一個(gè)回調(diào)函數(shù),沒有額外的性能損失,但是如果在一個(gè)組件中有很多的事件函數(shù)時(shí)這種在構(gòu)造函數(shù)中綁定this的方法會(huì)顯得繁瑣
  • 3、在給事件賦值時(shí)綁定this

    class MyComponent extends React.Component{ constructor(props){ super(props); this.state={ number:0 } } handleClick(){ ++this.state.number; console.log(this.state.number); } render(){ return( <div> <button type='button' onClick={this.handleClick.bind(this)}>點(diǎn)我</button> </div> ) } } ReactDOM.render(<MyComponent/>,document.getElementById('example')); 
            
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 注:但是此方法在每次render時(shí)都會(huì)重新創(chuàng)建一個(gè)新的函數(shù),性能有一定的損失,但在事件處理函數(shù)需要傳參數(shù)時(shí),這種方法就比較好

事件流

在該示例中,3個(gè)div嵌套顯示,并且每個(gè)元素上均綁定onClick事件。當(dāng)用戶點(diǎn)擊紅色區(qū)域的div元素時(shí),可以看到,控制臺(tái)先后輸出了child -> parent -> ancestor,這是因?yàn)樵赗eact的事件處理系統(tǒng)中,默認(rèn)的事件流就是冒泡。

const style={ child:{ width:'100px', height:'100px', background:'red' }, parent:{ width:'150px', height:'150px', background:'blue' }, ancestor:{ width:'200px', height:'200px', background:'green' } } class Example extends React.Component{ render(){ return( <div onClickCapture={()=> console.log('ancestor')} style={style.ancestor}> <div onClickCapture={ ()=> console.log('parent')} style={style.parent}> <div onClickCapture={ ()=> console.log('child')} style={style.child}></div> </div> </div> ) } } ReactDOM.render(<Example/>,document.getElementById('example')); 
  • 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

在這里插入圖片描述

  • React默認(rèn)的事件觸發(fā)方式:冒泡方式
  • 若將事件觸發(fā)改為捕獲方式:需要在事件名后帶上 Capture 后綴
<div onClickCapture={()=> console.log('ancestor')} style={style.ancestor}> <div onClickCapture={ ()=> console.log('parent')} style={style.parent}> <div onClickCapture={ ()=> console.log('child')} style={style.child}></div> </div> </div> 
  • 1
  • 2
  • 3
  • 4
  • 5

事件委托

在合成事件系統(tǒng)中,所有的事件都是綁定在document元素上,即雖然在某個(gè)React元素上綁定了事件,但是,最后事件都委托給document統(tǒng)一觸發(fā)。因此,在合成事件中只能阻止合成事件中的事件傳播

React 阻止的事件流,并沒有阻止真正DOM元素的事件觸發(fā),還是按照冒泡的方式,層層將事件交給上級(jí)元素進(jìn)行處理,最后事件傳播到docuement,觸發(fā)合成事件,在合成事件中,child觸發(fā)時(shí),e.stopPropagation() 被調(diào)用,合成事件中的事件被終止。因此,合成事件中的stopPropagation無法阻止事件在真正元素上的傳遞,它只阻止合成事件中的事件流。相反,如果綁定一個(gè)真正的事件,那么,合成事件則會(huì)被終止。

  • 默認(rèn)事件流是冒泡的,所有事件統(tǒng)一由document觸發(fā),在React中阻止冒泡方法是調(diào)用e.stopPropagation()
  • React的合成事件是可以找到原生的事件對(duì)象
  • React中的合成事件中只有一個(gè)全局對(duì)象event,該對(duì)象不是原生的event,但通過它可以獲得event對(duì)象的部分屬性。每個(gè)事件觸發(fā)完后React的全局對(duì)象event就會(huì)被清空,因此不能在異步操作使用

事件類型:
在這里插入圖片描述

收集表單數(shù)據(jù)

非受控組件

表單數(shù)據(jù)由DOM本身處理。即不受setState()的控制,與傳統(tǒng)的HTML表單輸入相似,input輸入值即顯示最新值(使用 ref 從DOM獲取表單值),即不受React控制改變表單元素提交的值的方式,稱為:“非受控組件”

class Login extends React.Component{ handleSubmit = (event)=>{ event.preventDefault() //阻止表單提交 const {username,password} = this alert(`你輸入的用戶名是:${username.value},你輸入的密碼是:${password.value}`) } render(){ return( <form onSubmit={this.handleSubmit}> 用戶名:<input ref={c => this.username = c} type="text" name="username"/> 密碼:<input ref={c => this.password = c} type="password" name="password"/> <button>登錄</button> </form> ) } } //渲染組件 ReactDOM.render(<Login/>,document.getElementById('test')) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

受控組件

在HTML中,標(biāo)簽<input><textarea>、<select>的值的改變通常是根據(jù)用戶輸入進(jìn)行更新。在React中,可變狀態(tài)通常保存在組件的狀態(tài)屬性中,并且只能使用 setState() 更新,而呈現(xiàn)表單的React組件也控制著在后續(xù)用戶輸入時(shí)該表單中發(fā)生的情況,以這種由React控制的輸入表單元素而改變其值的方式,稱為:“受控組件”。

class Login extends React.Component{ //初始化狀態(tài) state = { username:'', //用戶名 password:'' //密碼 } //保存用戶名到狀態(tài)中 saveUsername = (event)=>{ this.setState({username:event.target.value}) } //保存密碼到狀態(tài)中 savePassword = (event)=>{ this.setState({password:event.target.value}) } //表單提交的回調(diào) handleSubmit = (event)=>{ event.preventDefault() //阻止表單提交 const {username,password} = this.state alert(`你輸入的用戶名是:${username},你輸入的密碼是:${password}`) } render(){ return( <form onSubmit={this.handleSubmit}> 用戶名:<input onChange={this.saveUsername} type="text" name="username"/> 密碼:<input onChange={this.savePassword} type="password" name="password"/> <button>登錄</button> </form> ) } } //渲染組件 ReactDOM.render(<Login/>,document.getElementById('test')) 
  • 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

受控和非受控元素都有其優(yōu)點(diǎn),根據(jù)具體情況選擇

特征 非受控制 受控
一次性檢索(例如表單提交)
及時(shí)驗(yàn)證 ×
有條件的禁用提交按鈕 ×
執(zhí)行輸入格式 ×
一個(gè)數(shù)據(jù)的幾個(gè)輸入 ×
動(dòng)態(tài)輸入 ×

函數(shù)柯里化

高階函數(shù):如果一個(gè)函數(shù)符合下面2個(gè)規(guī)范中的任何一個(gè),那該函數(shù)就是高階函數(shù)。

  1. 若A函數(shù),接收的參數(shù)是一個(gè)函數(shù),那么A就可以稱之為高階函數(shù)
  2. 若A函數(shù),調(diào)用的返回值依然是一個(gè)函數(shù),那么A就可以稱之為高階函數(shù)

常見的高階函數(shù)有:Promise、setTimeout、arr.map()等等

函數(shù)的柯里化:通過函數(shù)調(diào)用繼續(xù)返回函數(shù)的方式,實(shí)現(xiàn)多次接收參數(shù)最后統(tǒng)一處理的函數(shù)編碼形式。

function sum(a){ return(b)=>{ return (c)=>{ return a+b+c } } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

函數(shù)柯里化的實(shí)現(xiàn)

class Login extends React.Component{ //初始化狀態(tài) state = { username:'', //用戶名 password:'' //密碼 } //保存表單數(shù)據(jù)到狀態(tài)中 saveFormData = (dataType)=>{ return (event)=>{ this.setState({[dataType]:event.target.value}) } } //表單提交的回調(diào) handleSubmit = (event)=>{ event.preventDefault() //阻止表單提交 const {username,password} = this.state alert(`你輸入的用戶名是:${username},你輸入的密碼是:${password}`) } render(){ return( <form onSubmit={this.handleSubmit}> 用戶名:<input onChange={this.saveFormData('username')} type="text" name="username"/> 密碼:<input onChange={this.saveFormData('password')} type="password" name="password"/> <button>登錄</button> </form> ) } } //渲染組件 ReactDOM.render(<Login/>,document.getElementById('test')) 
  • 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

































藍(lán)藍(lán)設(shè)計(jì)建立了UI設(shè)計(jì)分享群,每天會(huì)分享國(guó)內(nèi)外的一些優(yōu)秀設(shè)計(jì),如果有興趣的話,可以進(jìn)入一起成長(zhǎng)學(xué)習(xí),請(qǐng)掃碼藍(lán)小助,報(bào)下信息,藍(lán)小助會(huì)請(qǐng)您入群。歡迎您加入噢~~希望得到建議咨詢、商務(wù)合作,也請(qǐng)與我們聯(lián)系。

分享此文一切功德,皆悉回向給文章原作者及眾讀者.

轉(zhuǎn)自:csdn 免責(zé)聲明:藍(lán)藍(lán)設(shè)計(jì)尊重原作者,文章的版權(quán)歸原作者。如涉及版權(quán)問題,請(qǐng)及時(shí)與我們?nèi)〉寐?lián)系,我們立即更正或刪除。

藍(lán)藍(lán)設(shè)計(jì)www.bouu.cn )是一家專注而深入的界面設(shè)計(jì)公司,為期望卓越的國(guó)內(nèi)外企業(yè)提供卓越的UI界面設(shè)計(jì)、BS界面設(shè)計(jì) 、 cs界面設(shè)計(jì) 、 ipad界面設(shè)計(jì) 、 包裝設(shè)計(jì) 、 圖標(biāo)定制 、 用戶體驗(yàn) 、交互設(shè)計(jì)、 網(wǎng)站建設(shè) 、平面設(shè)計(jì)服務(wù)

分享本文至:

日歷

鏈接

個(gè)人資料

存檔