
這是一個(gè)超強(qiáng)的特性。仔細(xì)看完你就能體會(huì)。
在 html 的基礎(chǔ)知識(shí)中,表單是很重要的一個(gè)環(huán)節(jié)。但是由于各種原因,原生的表單開(kāi)發(fā)方式相關(guān)知識(shí)被部分前端開(kāi)發(fā)所遺忘,他們對(duì) form action,formdata 有一種陌生感。
因此,當(dāng)看到有消息稱 React 19 支持了 form action 之后,許多前端感覺(jué)有點(diǎn)懵。不知道這是啥。這篇文章就先給大家科普一下相關(guān)的知識(shí)。
先來(lái)看一段簡(jiǎn)單的代碼。
<form id="form" method="get"> First name: <input type="text" value="Jake" name="fname"> Last name: <input type="text" value="Ma" name="lname"> <input type="submit" value="提交"></form>當(dāng)我們使用表單 form 元素時(shí),內(nèi)部的表單元素可以根據(jù) name 屬性與 value 值自動(dòng)組合成一個(gè)完整的序列化表單對(duì)象。我們不再需要額外去拼接他們。
合成的序列化對(duì)象,我們稱之為 FormData, 這是一個(gè)特殊的對(duì)象。我們可以直接通過(guò)如下方式獲取到該對(duì)象。
let formdata = new FormData(form)console.log(formdata.get('fname'))console.log(formdata.get('lname'))i
我們無(wú)法直接觀察到 FormData 的值,需要使用 .get 方法來(lái)獲取。
FormData 也可以被網(wǎng)絡(luò)請(qǐng)求支持,例如我們可以把 FormData 對(duì)象作為 fetch 請(qǐng)求的 body,直接發(fā)送。
form.onsubmit = async e => { e.preventDefault() const response = await fetch('/post/user', { method: 'POST', body: new FormData(form) }) let res = await response.json() // do something}在這個(gè)案例中,當(dāng) type='submit' 的按鈕點(diǎn)擊提交時(shí),onsubmit 就會(huì)觸發(fā),我們可以在這個(gè)回調(diào)函數(shù)里執(zhí)行自己的提交邏輯。
?
HTTP 中 content-type 字段有專門支持 FormData 的值,如下所示:
Content-Type: multipart/form-data除此之外,我們可以使用 form 元素的 action 屬性來(lái)簡(jiǎn)化提交。不過(guò)它的表現(xiàn)會(huì)不太一樣。
action 接收一個(gè) URL 作為參數(shù),可以是絕對(duì)路徑,也是可以相對(duì)路徑。它表示攜帶表單數(shù)據(jù)向該地址發(fā)送請(qǐng)求。默認(rèn)情況下頁(yè)面會(huì)跳轉(zhuǎn)到指定的 URL 地址。
<form id="form" action="xx.html" method="post"> First name: <input type="text" value="Jake" name="fname"> Last name: <input type="text" value="Ma" name="lname"> <input type="submit" value="提交"></form>服務(wù)端可以攔截該地址,并定義響應(yīng)行為。
這樣做的好處就是我們可以簡(jiǎn)化提交行為的代碼。無(wú)需使用 JavaScript 對(duì)邏輯進(jìn)行任何額外的處理,就能完成一次提交操作。在沒(méi)有額外要求的情況下,我們可以非常方便的使用這種方式來(lái)提交表單數(shù)據(jù),上傳文件等。
FormData API 如下圖所示。

學(xué)習(xí)了這些基礎(chǔ)知識(shí)之后,我們來(lái)完成一個(gè)比較簡(jiǎn)單的案例。我們?cè)诒韱沃休斎胄畔ⅲ研畔⒂涗浾故驹谝粋€(gè)列表中。案例演示效果如下

首先我們要定義一個(gè)數(shù)據(jù),用于存儲(chǔ)列表。
const [posts, setPosts] = useState([])然后在 jsx 中,定義一個(gè)表單內(nèi)容,和列表渲染。
<div> <div>基礎(chǔ)的表單提交案例</div> <form action={action}> <div className="form_item"> <div className="label">Title</div> <input name='title' type="text" placeholder='Enter title' /> </div> <div className="form_item"> <div className="label">Name</div> <input name='content' type="text" placeholder='Enter you name' /> </div> <div className="form_item"> <button className='primary' type='submit'>Submit</button> </div> </form> <ul className='_07_list'> {posts.map((post, index) => ( <div key={`${post.title}-${index}`} className='_07_item'> <h2>{post.title}</h2> <p>{post.content}</p> </div> ))} </ul></div>提交之后的邏輯在 action 中處理,action 回調(diào)函數(shù)能拿到最新的 formdata。然后把對(duì)應(yīng)的數(shù)據(jù)拿出來(lái),設(shè)置到 posts 里面即可。
function action(data) { const title = data.get('title') const content = data.get('content') if (title && content) { setPosts([...posts, {title, content}]) }}我們可以簡(jiǎn)單擴(kuò)展一下,在這個(gè)基礎(chǔ)之上做一些校驗(yàn)。我們把其中一個(gè) input 做一些簡(jiǎn)單的調(diào)整。
<input onInput={onInput} name='content' type="text" placeholder='Enter you name' required pattern={'abc'}/>在 css 中,新增如果校驗(yàn)不通過(guò)的樣式。
input:invalid { border: 1px dashed red;}演示效果如下:

我們還可以通過(guò) input 的 onInput 事件對(duì)驗(yàn)證樣式進(jìn)行自定義。
function onInput(event) { let input = event.target console.log(input.validity) if (input.validity.valid) { console.log('xxxxx', input.validity) }}
這里面有許多狀態(tài)可以支持我們做許多自己的擴(kuò)展。
這里大家需要注意的一個(gè)小細(xì)節(jié)就是,許多針對(duì)表單功能增強(qiáng)的 API,都不是從 react 中引入,而是從 react-dom 中引入。

第一時(shí)間我還沒(méi)想通這到底咋回事。感覺(jué)好奇怪。后來(lái)我才意識(shí)到,這對(duì)于服務(wù)端渲染有著巨大的劃時(shí)代的重要意義。
在評(píng)估網(wǎng)頁(yè)性能中,有一個(gè)重要的性能指標(biāo):TTI:可交互時(shí)間。頁(yè)面加載完成,并且首屏顯示,并且頁(yè)面可以交互。
但是,在以前的服務(wù)端渲染項(xiàng)目中,想要頁(yè)面元素可以被點(diǎn)擊,可交互,需要經(jīng)歷一個(gè)重要的過(guò)程,那就是 Hydrate 水合。意思就是說(shuō),第一時(shí)間從服務(wù)端給到頁(yè)面上的只是字符串,并不具備可交互功能,它需要瀏覽器渲染之后,變成 DOM 元素,再通過(guò) React 水合之后,再變成 React 組件,然后才可以正常點(diǎn)擊交互。
因此,React 服務(wù)端渲染項(xiàng)目雖然首屏直出理論上會(huì)快一些,但是 TTI 要多經(jīng)歷一個(gè)水合的過(guò)程,那么可交互時(shí)間等待就比較久了。
?
其實(shí)也不一定,處理不好,服務(wù)端渲染項(xiàng)目也會(huì)更慢。
React 19 支持的 form action,實(shí)際上是極大的利用了瀏覽器的自帶的表單能力,它要可交互,并不需要經(jīng)歷水合過(guò)程,瀏覽器渲染成 DOM 就可以正常交互了。
道友們,誰(shuí)懂啊,這就有點(diǎn)厲害了。
?
有的服務(wù)端渲染項(xiàng)目首屏渲染時(shí)間只需要不到 1s,但是首次可交互時(shí)間,能長(zhǎng)達(dá) 8s 之久。從這個(gè)簡(jiǎn)單的數(shù)據(jù)對(duì)比,你就能領(lǐng)會(huì)不需要水合是多大的提升了。
這不僅在客戶端組件中,直接掙脫了之前受控組件在性能上的桎梏,還更進(jìn)一步在服務(wù)端渲染項(xiàng)目有更強(qiáng)的體現(xiàn)。如果一旦跟 next.js 有機(jī)結(jié)合...
不得不佩服 React 團(tuán)隊(duì)在設(shè)計(jì)項(xiàng)目架構(gòu)解決方案上的超前思維。
React form Action 是一個(gè)很小的知識(shí)點(diǎn),但是它代表的是表單開(kāi)發(fā)的另一種思路,是一種開(kāi)發(fā)方式的隆重回歸。因此這要求我們對(duì) HTML 本身已經(jīng)支持的表單能力要有所了解。我們?cè)诤罄m(xù)的開(kāi)發(fā)使用中,會(huì)逐漸弱化受控組件的使用,這會(huì)帶來(lái)開(kāi)發(fā)體驗(yàn)和性能上的提升。
除此之外,React 在表單開(kāi)發(fā)中還提供了許多功能增強(qiáng)的 hook,我們?cè)诤罄m(xù)的分享慢慢學(xué)習(xí)。
本文鏈接:http://m.www897cc.com/showinfo-26-100724-0.htmlReact 支持 Form Action 是在作妖?不,它是一種重磅回歸
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com