摘要:函數(shù)更新屬性,進而更新元素的值。由于箭頭函數(shù)存在于父組件中,所以中的指向父組件。一旦表單被提交,的值就被設(shè)置為。遺憾的是,沒有節(jié)點是包含了集合的。在這種情況下,這個節(jié)點列表包含三個節(jié)點和被選中的值。
原文地址:React Forms: Using Refs
原文作者:Loren Stewart
譯者:萌萌
校對者:小 boy
React 提供了兩種從 元素中獲取值的標(biāo)準(zhǔn)方法。第一種方法是實現(xiàn)所謂的受控組件 (可以看我博客里發(fā)表的文章) ,第二種方法是使用 React 的 ref 屬性。
受控組件很重,被展示的值和組件的 state 綁定是它的特性。我們通過執(zhí)行一個附著在 form 元素上的 onChange 事件句柄,來更新被展示的值。onChange 函數(shù)更新 state 屬性,進而更新 form 元素的值。
(在看到下面的文章之前,如果你只是想看相應(yīng)的示例代碼:請移步這里)
受控組件示例:
import React, { Component } from "react"; class ControlledCompExample extends Component { constructor() { super(); this.state = { fullName: "" } } handleFullNameChange = (e) => { this.setState({ fullName: e.target.value }) } handleSubmit = (e) => { e.preventDefault(); console.log(this.state.fullName) } render() { return (); } } export default ControlledCompExample;
input 的值是 this.state.fullName (在第7行和第26行)。 onChange 函數(shù)是 handleFullNameChange (第 10 - 14 行和第 27 行)。
受控組件最主要的優(yōu)勢是:
1、便于驗證用戶的輸入
2、可以根據(jù)受控組件的值動態(tài)地渲染其他組件。例如:一個用戶在下拉列表中選擇的值(如“dog” 或者 “cat” )可以控制在 form 中渲染的其他 form 組件(例如:一個設(shè)置品種的復(fù)選框)
受控組件的缺點是要寫大量的代碼。你需要通過 props 把 state 屬性傳遞給 form 元素,還需要一個函數(shù)來更新這個屬性的值。
對于單一表單元素來說這真的不是什么問題 —— 但是如果你需要一個龐大并且復(fù)雜的表單(不需要動態(tài)渲染或者實時驗證),過度使用受控表單會讓你書寫成噸的代碼。
從 form 元素取值的簡便的方法是使用 ref 屬性。我們用不同的方式來應(yīng)對不同的 form 元素和組件結(jié)構(gòu),所以這篇文章剩下的內(nèi)容分為以下幾個部分。
文本輸入框、數(shù)字輸入框和選擇框
子組件通過 props 傳值給父組件
Radio 標(biāo)簽集合
Checkbox 標(biāo)簽集合
1、文本輸入框、數(shù)字輸入框和選擇框使用 ref 的最簡單的例子是文本和數(shù)字 input 元素。我們在 input 的 ref 屬性里添加一個把 input 本身作為參數(shù)的箭頭函數(shù)。我喜歡把參數(shù)命名為和元素本身一樣的的名字,就像下面的第三行那個樣子:
this.fullName = input} />
由于該參數(shù)是 input 元素本身的別名,你可以隨心所欲地為它命名:
this.amount = cashMoney} />
接著你可以拿到該參數(shù),并將它賦值給當(dāng)前 class 內(nèi) this 關(guān)鍵字上掛載的屬性(譯者注:這里的 class 指的是 JSX 所處的 React 組件 class)。input(例如: DOM 節(jié)點)可以通過 this.fullName 和 this.amount 來讀取。它的值可以通過 this.fullName.value 和 this.amount.value 來讀取。
選擇元素也可以用相同的方法(例如:下拉列表)。
選擇元素的值可以通過 this.petType.value 獲取。
2、子組件通過 props 傳值給父組件通過受控組件,父組件獲取子組件的值十分簡單 —— 父組件中已經(jīng)有這個值了(譯者注:在父組件中定義)!它被傳遞給子組件。同時 onChange 方法也被傳給子組件,用戶通過與 UI 互動(譯者注:觸發(fā) onChange)來更新該值。
你可以在我上篇文章的受控組件示例中看到它是如何運行的。
雖然該值已經(jīng)存在于受控組件的父組件中,但是當(dāng)使用 ref 的時候卻不是這樣。使用 ref 的時候,該值存在于 DOM 節(jié)點自身當(dāng)中,必須向上與父組件通信。
要將該值從子組件傳給父組件,父組件需要向子組件傳遞一個 鉤子 。然后子組件將節(jié)點掛載到 鉤子 上, 以便父組件讀取。
在我們更深入的探討之前先來看一些代碼。
import React, { Component } from "react"; class RefsForm extends Component { handleSubmit = (e) => { e.preventDefault(); console.log("first name:", this.firstName.value); this.firstName.value = "Got ya!"; } render() { return (); } } function CustomInput(props) { return (); } export default RefsForm;
通過上面的代碼,可以看到一個 form 組件 RefForm 和一個叫做 CustomInput 的 input 組件。通常,箭頭函數(shù)都是在 input 自身上面,但是從這(15 - 27 行)可以看到它是通過 props 傳遞的。由于箭頭函數(shù)存在于父組件中,所以 this.firstName 中的 this 指向父組件。
input 子組件的值被賦給父組件的 this.firstName 屬性,所以父組件可以獲得子組件的值。現(xiàn)在,父組件中的 this.firstName 指的是子組件中的 DOM 節(jié)點(例如: CustomInput 中的 input)。
父組件不僅可以訪問 input 中的 DOM 節(jié)點,還可以在父組件內(nèi)給節(jié)點的值賦值。在上文的第 7 行可以看到例子。一旦表單被提交, input 的值就被設(shè)置為 “Got ya!” 。
這種方式有點讓人摸不著頭腦,所以請仔細(xì)揣摩并敲代碼實踐一下,直至完全理解。
你可能會寫出來更好的 radio 和 checkbox 受控組件,但是如果你真的想要用 `ref` ,那么接下來的兩部分會幫到你。3、 Radio 標(biāo)簽集合
不像 text 和 number 這類 input 元素,radio 元素是成組出現(xiàn)的。每組中的元素都有相同的 name 屬性,就像這樣:
在 “pet” radio 標(biāo)簽集合中有三個選項 —— “cat”、“dog” 和 “ferret”。
由于我們關(guān)心的是整個集合的元素,所以給每個單選框設(shè)置 ref 并不是一個好主意。遺憾的是,沒有 DOM 節(jié)點是包含了 radio 集合的。
可以通過下面的三步來檢索出 radio 集合的值:
1、在 form 標(biāo)簽上設(shè)置 ref (下面的第20行)。
2、從 form 中取出這個 radio 集合。然后它應(yīng)該是 pet 集合(下面的第9行)。
此處返回一個節(jié)點列表和一個值。在這種情況下,這個節(jié)點列表包含三個 input 節(jié)點和被選中的值。
需要注意的是這個節(jié)點列表是個類數(shù)組,它沒有數(shù)組的方法。在下一部分中還有更多關(guān)于這個話題的內(nèi)容。
3、使用 . 方法來獲取這個集合的值(下面的第13行)。
import React, { Component } from "react"; class RefsForm extends Component { handleSubmit = (e) => { e.preventDefault(); // 從 form 中取出節(jié)點列表 // 它是一個類數(shù)組,沒有數(shù)組的方法 const { pet } = this.form; // radio 標(biāo)簽集合有 value 屬性 // 查看打印出來的數(shù)據(jù) console.log(pet, pet.value); } render() { return (); } } export default RefsForm;
如果你正在用子組件寫一個表單也是可行的。盡管組件中會有更多的邏輯,但是從 radio 集合中獲取值的方法是不變的。
import React, { Component } from "react"; class RefsForm extends Component { handleSubmit = (e) => { e.preventDefault(); // 從 form 中取出節(jié)點列表 // 它是一個類數(shù)組,沒有數(shù)組的方法 const { pet } = this.form; // radio 標(biāo)簽集合有 value 屬性 // 查看打印出來的數(shù)據(jù) console.log(pet, pet.value); } render() { return (4、 Checkbox 標(biāo)簽集合); } } function RadioSet(props) { return ({props.setOptions.map(option => { return ( ) })}); } export default RefsForm;
和 radio 標(biāo)簽集合不一樣, Checkbox 標(biāo)簽集合可能有多個值。導(dǎo)致獲取這些值會比獲取 radio 標(biāo)簽集合的值難一些。
可以通過下面的五步來檢索出 checkbox 標(biāo)簽集合被選中的值:
1、在 form 標(biāo)簽上設(shè)置 ref (下面的第27行)。
2、從 form 中取出這個checkbox 集合。然后它應(yīng)該是 pet 集合(第9行)。
此處返回一個節(jié)點列表和一個值
需要注意的是這個節(jié)點列表是一個類數(shù)組,它沒有數(shù)組的方法,然后我們就需要進行下面的這一步 ...
3、把這個節(jié)點列表轉(zhuǎn)換成一個數(shù)組,然后就可以使用數(shù)組的方法了(第 12 行的 checkboxArray )。
4、使用 Array.filter() 獲取選中的 checkbox (第 15 行的 checkedCheckboxes )。
5、使用 Array.map() 獲取選中的 checkbox 的唯一的值(第 19 行的 checkedCheckboxesValues )
import React, { Component } from "react"; class RefsForm extends Component { handleSubmit = (e) => { e.preventDefault(); // 從 form 中取出節(jié)點列表 // 它是一個類數(shù)組,沒有數(shù)組的方法 const { pet } = this.form; // 把節(jié)點列表轉(zhuǎn)換成一個數(shù)組 const checkboxArray = Array.prototype.slice.call(pet); // 僅取出被選中的 checkbox const checkedCheckboxes = checkboxArray.filter(input => input.checked); console.log("checked array:", checkedCheckboxes); // 使用 .map() 方法從每個被選中的 checkbox 中把值取出來 const checkedCheckboxesValues = checkedCheckboxes.map(input => input.value); console.log("checked array values:", checkedCheckboxesValues); } render() { return (); } } export default RefsForm;
使用子組件寫 checkbox 的方法和上一部分中寫 radio 的方法是一樣的。
import React, { Component } from "react"; class RefsForm extends Component { handleSubmit = (e) => { e.preventDefault(); // 從 form 中取出節(jié)點列表 // 它是一個類數(shù)組,沒有數(shù)組的方法 const { pet } = this.form; // 把節(jié)點列表轉(zhuǎn)換成一個數(shù)組 const checkboxArray = Array.prototype.slice.call(pet); // 僅取出被選中的 checkbox const checkedCheckboxes = checkboxArray.filter(input => input.checked); console.log("checked array:", checkedCheckboxes); // 使用 .map() 方法從每個被選中的 checkbox 中把值取出來 const checkedCheckboxesValues = checkedCheckboxes.map(input => input.value); console.log("checked array values:", checkedCheckboxesValues); } render() { return (結(jié)論); } } function CheckboxSet(props) { return ({props.setOptions.map(option => { return ( ) })}); } export default RefsForm;
如果你不需要:
1、實時監(jiān)視 form 元素的值(例如:為了基于用戶的輸入渲染之后的組件)
2、實時執(zhí)行自定義驗證方法
那么使用 ref 方法獲取 form 元素的值是一個很好的方法。
大多數(shù)情況下,越過受控組件使用 ref 最主要的價值是會寫更少的代碼。 checkbox ( radio 其次)是一個特例。對于 checkbox ,使用 ref 省下的代碼量是很少的,所以無法說是使用受控組件好還是 ref 好。
iKcamp原創(chuàng)新書《移動Web前端高效開發(fā)實戰(zhàn)》已在亞馬遜、京東、當(dāng)當(dāng)開售。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/85076.html
摘要:受控輸入框只會顯示通過傳入的數(shù)據(jù)。例如,數(shù)組中的元素將會渲染三個單選框或復(fù)選框。屬性接收一個布爾值,用來表示組件是否應(yīng)該被渲染成選中狀態(tài)。 原文地址:React.js Forms: Controlled Components 原文作者:Loren Stewart 譯者:小 B0Y 校對者:珂珂君 本文涵蓋以下受控組件: 文本輸入框 數(shù)字輸入框 單選框 復(fù)選框 文本域 下拉...
摘要:通過表單添加任務(wù)在這個步驟,我們將為用戶在列表上添加輸入框。在中,這是一種監(jiān)聽瀏覽器事件的方式,就像是在表單上有提交事件一樣。這對一個任務(wù)列表來說并不是非常好。在下一步,我們將給待辦事宜的列表添加一個非常重要的功能已完成功能和刪除功能 通過表單(form)添加任務(wù) 在這個步驟,我們將為用戶在列表上添加輸入框。 首先,在App.jsx文件中App組件上添加表單吧。 Tod...
摘要:前端日報精選我是如何實現(xiàn)的在線升級熱更新功能的張鑫旭鑫空間鑫生活翻譯表單的運用第期晉升評審的套路異步編程的四種方式黃博客精選組件設(shè)計和分解思考掘金中文譯使登錄頁面變得正確掘金前端從強制開啟壓縮探究插件運行機制掘金個常用的簡 2017-06-28 前端日報 精選 我是如何實現(xiàn)electron的在線升級熱更新功能的? ? 張鑫旭-鑫空間-鑫生活【翻譯】React 表單: Refs 的運用【...
摘要:系列系列簡單模擬語法一系列合成事件與二系列算法實現(xiàn)分析三系列從到再到四系列與部分源碼解析五系列從使用了解的各種使用方案六的誕生他是的一種擴展語法。這個函數(shù)接受組件的實例或元素作為參數(shù),以存儲它們并使它們能被其他地方訪問。 React系列 React系列 --- 簡單模擬語法(一)React系列 --- Jsx, 合成事件與Refs(二)React系列 --- virtualdom di...
摘要:希望大家在這浮夸的前端圈里,保持冷靜,堅持每天花分鐘來學(xué)習(xí)與思考。 今天的React題沒有太多的故事…… 半個月前出了248個Vue的知識點,受到很多朋友的關(guān)注,都強烈要求再出多些React相前的面試題,受到大家的邀請,我又找了20多個React的使用者,他們給出了328道React的面試題,由我整理好發(fā)給大家,同時發(fā)布在了前端面試每日3+1的React專題,希望對大家有所幫助,同時大...
閱讀 2224·2019-08-30 15:54
閱讀 1960·2019-08-30 13:49
閱讀 679·2019-08-29 18:44
閱讀 834·2019-08-29 18:39
閱讀 1117·2019-08-29 15:40
閱讀 1538·2019-08-29 12:56
閱讀 3151·2019-08-26 11:39
閱讀 3104·2019-08-26 11:37