react中事件處理與柯里化的實(shí)現(xiàn)
1. 事件處理
React 中元素也可接受、處理事件,但是在語法上有一點(diǎn)不同。
在React 中所有事件的命名采用的是小駝峰,而非原生 DOM 的純小寫,所有事件需要我們傳入一個函數(shù),而非字符串。
例如:
const Button = () => {
const handleClick = () => {
console.log('click')
}
return <button onClick={handleClick}>click button</button>
}
當(dāng)事件的回調(diào)函數(shù)比較簡單時,我們也可以簡寫箭頭匿名函數(shù),例如:
const Button = () => {
return (
<button
onClick={() => console.log('click')}
>
click button
</button>)
}
阻止默認(rèn)行為
在React 中不能通過返回 false 來阻止默認(rèn)行為,例如表單提交、a標(biāo)簽跳轉(zhuǎn)。我們必須要通過顯式調(diào)用 preventDefault 函數(shù),來阻止這些默認(rèn)行為。
const Link = () => {
return <a
rel="external nofollow" rel="external nofollow"
onClick={(e) => e.preventDefault()}
>
link
</a>
}
合成事件
在 React 中幾乎所有的事件處理函數(shù),都是一個 (event)=>void 函數(shù),如果我們使用 typescript,可以清晰的看到每個事件對應(yīng)的函數(shù)類型,React 自身也聲明了很多的事件與事件處理函數(shù)類型,例如鼠標(biāo)事件:MouseEvent<T = Element> 與 MouseEventHandler<T = Element>,我們在使用時可以根據(jù)自己的喜歡,是定義函數(shù)類型還是定義參數(shù)類型,就像這樣:
const Link = () => {
const handleClick = (e: MouseEvent) => {
e.preventDefault()
console.log('click')
}
const handleMouseEnter:MouseEventHandler = (e) => {
console.log('mouse enter')
}
return <a
rel="external nofollow" rel="external nofollow"
onMouseEnter={handleMouseEnter}
onClick={handleClick}
>
link
</a>
}
在 React 中,所有事件都是 React 根據(jù) W3C 規(guī)范定義的合成事件,所以我們完全不用擔(dān)心兼容性問題,React 事件與原生事件不完全相同。
2. 柯里化
柯里化這個名稱對于 Android 開發(fā)可能有點(diǎn)陌生,因?yàn)槲覀円话闶褂?Java 開發(fā),因?yàn)樵缙诘?Java 不支持函數(shù)式編程(FP),而柯里化是一個函數(shù)式編程思想。
簡而言之是將一個多參函數(shù)變成單參數(shù)函數(shù),舉個栗子:
//柯里化后的單參數(shù)函數(shù)
function sumCurrying(a) {
return (b) => {
return (c) => {
return a + b + c;
};
};
}
//普通的多參數(shù)函數(shù)
function sumNormal(a, b, c) {
return a + b + c
}
console.log(sumCurrying(1)(2)(3));
console.log(sumNormal(1, 2, 3));
柯里化的本質(zhì),就是高階函數(shù)的一個特性:函數(shù)的返回值可以是一個函數(shù)。
上面的例子,似乎有點(diǎn)脫褲子放屁,看似毫無意義。但實(shí)際工程中,柯里化是一個非常實(shí)用的小 trick。最常用在事件處理需要傳入值的場景。
我們在上面說過了,React 中的事件回調(diào)函數(shù)是有固定的函數(shù)類型的,幾乎都是 (event)=>void 函數(shù)。我們需要傳入一些參數(shù)給這個事件處理函數(shù)呢?
const List = () => {
const list = [
{ id: 1, name: 'tom' },
{ id: 2, name: 'jerry' },
{ id: 3, name: 'jack' },
{ id: 4, name: 'lily' },
]
const handleClick = (id: number) => {
console.log(id)
}
return <ul>
{list.map(item => <li
onClick={() => handleClick(item.id)}
key={item.id}
>
{item.name}
</li>
)}
</ul>
}
這看起來似乎很不優(yōu)雅,我們已經(jīng)聲明了 handle 函數(shù),卻又不得不在事件處理函數(shù)中寫行內(nèi)的箭頭函數(shù),如何才能更加優(yōu)雅的處理呢?
其實(shí)很簡單,我們只需要在原本的 handle 函數(shù)中,插入一個箭頭即可,就像這樣:
//before
const handleClick = (id: number) => {
console.log(id)
}
//after
const handleClick = (id: number) => (e:MouseEvent) => {
console.log(id)
}
然后我們的 onClick 事件回調(diào)函數(shù)就可以改成 onClick={handleClick(item.id)} ,這樣看起來是不是就更加優(yōu)雅了呢?
其實(shí)這種設(shè)計(jì)思想可以說是一說就透,只不過我現(xiàn)在告訴你,這種思想就叫做:柯里化。
柯里化的目的
你可能會問我柯里化看起來只是讓我們的代碼優(yōu)雅了一點(diǎn),在目前看來似乎沒有什么本質(zhì)上的變化。
但其實(shí)柯里化幫助我們實(shí)現(xiàn)了函數(shù)的一變多,我們用一個日志輸出的函數(shù)作為例子:
//原始函數(shù)
const log = (date, importance, message) => {
alert(`[${date.getHours()}:${date.getMinutes()}] [${importance}] ${message}`);
}
//柯里化
const logCurry = (date) => (importance) => (message) => {
alert(`[${date.getHours()}:${date.getMinutes()}] [${importance}] ${message}`);
}
柯里化后,函數(shù)變成這樣調(diào)用:logCurry(new Date())("DEBUG")("some debug");
現(xiàn)在我們相當(dāng)于擁有這些函數(shù):
// logNow 會是帶有固定第一個參數(shù)的日志的函數(shù)
let logNow = logCurry(new Date());
// 使用它
logNow("INFO", "message"); // [HH:mm] INFO message
// debugNow 會是帶有固定第一個參數(shù)與第二個參數(shù)的函數(shù)
let debugNow = logNow("DEBUG");
debugNow("message"); // [HH:mm] DEBUG message
看起來只是增加了幾個箭頭,實(shí)際上我們函數(shù)的靈活性大為增加。通過固定不同的參數(shù),我們從一個函數(shù)聲明獲得了多個函數(shù)。
一個簡單的例子
const Form = () => {
const [form, setForm] = React.useState({});
const update = (name) => (event) => {
setForm({
...form,
[name]: event.target.value,
});
}
const handleSubmit = (event) => {
event.preventDefault();
alert(`${JSON.stringify(form)}`);
}
return (
<div>
<h1>柯里化表單</h1>
<FormItem label="用戶名" name='username' update={update} />
<FormItem label="昵稱" name='nickname' update={update} />
<FormItem label="郵箱" name='email' update={update} />
<button onClick={handleSubmit}>提交</button>
</div>
)
}
const FormItem = ({ label, name, update }) => {
return (
<div style={{ 'display': 'flex' }}>
<label>{label}</label>
<input onChange={update(name)} type="text" placeholder={`請輸入${label}`} />
</div>
);
};到此這篇關(guān)于react中事件處理與柯里化的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)react 事件處理與柯里化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React利用路由實(shí)現(xiàn)登錄界面的跳轉(zhuǎn)
這篇文章主要介紹了React利用路由實(shí)現(xiàn)登錄界面的跳轉(zhuǎn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
解決React報錯No duplicate props allowed
這篇文章主要為大家介紹了React報錯No duplicate props allowed解決方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
一文詳解React中如何實(shí)現(xiàn)組件懶加載
懶加載是一種優(yōu)化技術(shù),旨在延遲加載不必要的資源,直到它們真正需要時再進(jìn)行加載,那么React的懶加載是如何實(shí)現(xiàn)的呢,下面小編就來和大家詳細(xì)講講吧2025-03-03
react-native使用leanclound消息推送的方法
這篇文章主要介紹了react-native使用leanclound消息推送的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-08-08
react vite使用import.meta.glob批量導(dǎo)入路由方式
文章介紹了如何通過動態(tài)引入模塊中的路由信息,簡化了傳統(tǒng)的路由管理方式,無需單獨(dú)引入每個模塊的路由2025-10-10
在React中使用React.createRef:更優(yōu)雅的DOM引用方式
React提供了多種方式來引用DOM元素,其中React.createRef()是一種更為現(xiàn)代、更優(yōu)雅的方式,在這篇文章中,我們將深入了解React.createRef()的應(yīng)用,以及它為開發(fā)者帶來的便利,感興趣的朋友一起看看吧2024-01-01
React ts模式使用http-proxy-middleware代理時訪問報404問題
這篇文章主要介紹了React ts模式使用http-proxy-middleware代理時訪問報404問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-07-07

