摘要:受控輸入框只會(huì)顯示通過傳入的數(shù)據(jù)。例如,數(shù)組中的元素將會(huì)渲染三個(gè)單選框或復(fù)選框。屬性接收一個(gè)布爾值,用來表示組件是否應(yīng)該被渲染成選中狀態(tài)。
原文地址:React.js Forms: Controlled Components
原文作者:Loren Stewart
譯者:小 B0Y
校對(duì)者:珂珂君
本文涵蓋以下受控組件:
文本輸入框
數(shù)字輸入框
單選框
復(fù)選框
文本域
下拉選擇框
同時(shí)也包含:
表單數(shù)據(jù)的清除和重置
表單數(shù)據(jù)的提交
表單校驗(yàn)
介紹點(diǎn)擊這里直接查看示例代碼。
查看示例。
請(qǐng)?jiān)谶\(yùn)行示例時(shí)打開瀏覽器的控制臺(tái)。
在學(xué)習(xí) React.js 時(shí)我遇到了一個(gè)問題,那就是很難找到受控組件的真實(shí)示例。受控文本輸入框的例子倒是很豐富,但復(fù)選框、單選框、下拉選擇框的例子卻不盡人意。
本文列舉了真實(shí)的受控表單組件示例,要是我在學(xué)習(xí) React 的時(shí)候早點(diǎn)發(fā)現(xiàn)這些示例就好了。除了日期和時(shí)間輸入框需要另開篇幅詳細(xì)討論,文中列舉了所有的表單元素。
有時(shí)候,為了減少開發(fā)時(shí)間,有時(shí)候人們很容易為了一些東西(譬如表單元素)引入一個(gè)庫。而對(duì)于表單,我發(fā)現(xiàn)當(dāng)需要添加自定義行為或表單校驗(yàn)時(shí),使用庫會(huì)讓事情變得更復(fù)雜。不過一旦掌握合適的 React 模式,你會(huì)發(fā)現(xiàn)構(gòu)建表單組件并非難事,并且有些東西完全可以自己動(dòng)手,豐衣足食。請(qǐng)把本文的示例代碼當(dāng)作你創(chuàng)建表單組件的起點(diǎn)或靈感之源。
除了提供多帶帶的組件代碼,我還將這些組件放進(jìn)表單中,方便你理解子組件如何更新父組件 state ,以及接下來父組件如何通過 props(單向數(shù)據(jù)流)更新子組件。
注意:本表單示例由很贊的 create-react-app 構(gòu)建配置生成,如果你還沒有安裝該構(gòu)建配置,我強(qiáng)烈推薦你安裝一下(npm install -g create-react-app)。目前這是搭建 React 應(yīng)用最簡(jiǎn)單的方式。
什么是受控組件?受控組件有兩個(gè)特點(diǎn):
受控組件提供方法,讓我們?cè)诿看?onChange 事件發(fā)生時(shí)控制它們的數(shù)據(jù),而不是一次性地獲取表單數(shù)據(jù)(例如用戶點(diǎn)提交按鈕時(shí))。“被控制“ 的表單數(shù)據(jù)保存在 state 中(在本文示例中,是父組件或容器組件的 state)。
(譯注:這里作者的意思是通過受控組件, 可以跟蹤用戶操作表單時(shí)的數(shù)據(jù),從而更新容器組件的 state ,再單向渲染表單元素 UI。如果不使用受控組件,在用戶實(shí)時(shí)操作表單時(shí),比如在輸入框輸入文本時(shí),不會(huì)同步到容器組件的 state,雖然能同步輸入框本身的 value,但與容器組件的 state 無關(guān),因此容器組件只能在某一時(shí)間,比如提表單時(shí)一次性地拿到(通過 refs 或者選擇器)表單數(shù)據(jù),而難以跟蹤)
受控組件的展示數(shù)據(jù)是其父組件通過 props 傳遞下來的。
這個(gè)單向循環(huán) —— (數(shù)據(jù))從(1)子組件輸入到(2)父組件的 state,接著(3)通過 props 回到子組件,就是 React.js 應(yīng)用架構(gòu)中單向數(shù)據(jù)流的含義。
表單結(jié)構(gòu)我們的頂級(jí)組件叫做 App,這是它的代碼:
import React, { Component } from "react"; import "../node_modules/spectre.css/dist/spectre.min.css"; import "./styles.css"; import FormContainer from "./containers/FormContainer"; class App extends Component { render() { return (); } } export default App;React.js Controlled Form Components
App 只負(fù)責(zé)渲染 index.html 頁面。整個(gè) App 組件最有趣的部分是 13 行,FormContainer 組件。
插曲: 容器(智能)組件 VS 普通(木偶)組件是時(shí)候提及一下容器(智能)組件和普通(木偶)組件了。容器組件包含業(yè)務(wù)邏輯,它會(huì)發(fā)起數(shù)據(jù)請(qǐng)求或進(jìn)行其他業(yè)務(wù)操作。普通組件則從它的父(容器)組件接收數(shù)據(jù)。木偶組件有可能觸發(fā)更新 state (譯注:容器組件的 state)這類邏輯行為,但它僅通過從父(容器)組件傳入的方法來達(dá)到該目的。
注意: 雖然在我們的表單應(yīng)用里父組件就是容器組件,但我要強(qiáng)調(diào),并非所有的父組件都是容器組件。木偶組件嵌套木偶組件也是可以的。
回到應(yīng)用結(jié)構(gòu)FormContainer 組件包含了表單元素組件,它在生命周期鉤子方法 componentDidMount 里請(qǐng)求數(shù)據(jù),此外還包含更新表單應(yīng)用 state 的邏輯行為。在下面的預(yù)覽代碼里,我移除了表單元素的 props 和 change 事件處理方法,這樣看起來更簡(jiǎn)潔清晰(拉到文章底部,可以看到完整代碼)。
import React, {Component} from "react"; import CheckboxOrRadioGroup from "../components/CheckboxOrRadioGroup"; import SingleInput from "../components/SingleInput"; import TextArea from "../components/TextArea"; import Select from "../components/Select"; class FormContainer extends Component { constructor(props) { super(props); this.handleFormSubmit = this.handleFormSubmit.bind(this); this.handleClearForm = this.handleClearForm.bind(this); } componentDidMount() { fetch("./fake_db.json") .then(res => res.json()) .then(data => { this.setState({ ownerName: data.ownerName, petSelections: data.petSelections, selectedPets: data.selectedPets, ageOptions: data.ageOptions, ownerAgeRangeSelection: data.ownerAgeRangeSelection, siblingOptions: data.siblingOptions, siblingSelection: data.siblingSelection, currentPetCount: data.currentPetCount, description: data.description }); }); } handleFormSubmit() { // 提交邏輯寫在這 } handleClearForm() { // 清除表單邏輯寫在這 } render() { return (); }
我們勾勒出了應(yīng)用基礎(chǔ)結(jié)構(gòu),接下來我們一起瀏覽下每個(gè)子組件的細(xì)節(jié)。
該組件可以是 text 或 number 輸入框,這取決于傳入的 props。通過 React 的 PropTypes,我們可以非常好地記錄組件拿到的 props。如果漏傳 props 或傳入錯(cuò)誤的數(shù)據(jù)類型, 瀏覽器的控制臺(tái)中會(huì)出現(xiàn)警告信息。
下面列舉
SingleInput.propTypes = { inputType: React.PropTypes.oneOf(["text", "number"]).isRequired, title: React.PropTypes.string.isRequired, name: React.PropTypes.string.isRequired, controlFunc: React.PropTypes.func.isRequired, content: React.PropTypes.oneOfType([ React.PropTypes.string, React.PropTypes.number, ]).isRequired, placeholder: React.PropTypes.string, };
PropTypes 聲明了 prop 的類型(string、 number、 array、 object 等等),其中包括了必需(isRequired)和非必需的 prop,當(dāng)然它還有更多的用途(欲知更多細(xì)節(jié),請(qǐng)查看 React 文檔)。
下面我們逐個(gè)討論這些 PropType:
inputType:接收兩個(gè)字符串:"text" 或 "number"。該設(shè)置指定渲染 組件或 組件。
title:接收一個(gè)字符串,我們將它渲染到輸入框的 label 元素中。
name:輸入框的 name 屬性。
controlFunc:它是從父組件或容器組件傳下來的方法。因?yàn)樵摲椒⊕燧d在 React 的 onChange 處理方法上,所以每當(dāng)輸入框的輸入值改變時(shí),該方法都會(huì)被執(zhí)行,從而更新父組件或容器組件的 state。
content:輸入框內(nèi)容。受控輸入框只會(huì)顯示通過 props 傳入的數(shù)據(jù)。
placeholder:輸入框的占位符文本,是一個(gè)字符串。
既然該組件不需要任何邏輯行為和內(nèi)部 state,那我們可以將它寫成純函數(shù)組件(pure functional component)。我們將純函數(shù)組件賦值給一個(gè) const 常量上。下面是
import React from "react"; const SingleInput = (props) => (); SingleInput.propTypes = { inputType: React.PropTypes.oneOf(["text", "number"]).isRequired, title: React.PropTypes.string.isRequired, name: React.PropTypes.string.isRequired, controlFunc: React.PropTypes.func.isRequired, content: React.PropTypes.oneOfType([ React.PropTypes.string, React.PropTypes.number, ]).isRequired, placeholder: React.PropTypes.string, }; export default SingleInput;
接著,我們用 handleFullNameChange 方法(它被傳入到 controlFunc prop 屬性)來更新
// FormContainer.js handleFullNameChange(e) { this.setState({ ownerName: e.target.value }); } // constructor 方法里別漏掉了這行: // this.handleFullNameChange = this.handleFullNameChange.bind(this);
隨后我們將容器組件更新后的 state (譯注:這里指 state 上掛載的 ownerName 屬性)通過 content prop 傳回
選擇組件(就是下拉選擇組件),接收以下 props:
Select.propTypes = { name: React.PropTypes.string.isRequired, options: React.PropTypes.array.isRequired, selectedOption: React.PropTypes.string, controlFunc: React.PropTypes.func.isRequired, placeholder: React.PropTypes.string };
name:填充表單元素上 name 屬性的字符串變量。
options:是一個(gè)數(shù)組(本例是字符串?dāng)?shù)組)。通過在組件的 render 方法中使用 props.options.map(), 該數(shù)組中的每一項(xiàng)都會(huì)被渲染成一個(gè)選擇項(xiàng)。
selectedOption:用以顯示表單填充的默認(rèn)選項(xiàng),或用戶已選擇的選項(xiàng)(例如當(dāng)用戶編輯之前已提交過的表單數(shù)據(jù)時(shí),可以使用這個(gè) prop)。
controlFunc:它是從父組件或容器組件傳下來的方法。因?yàn)樵摲椒⊕燧d在 React 的 onChange 處理方法上,所以每當(dāng)改變選擇框組件的值時(shí),該方法都會(huì)被執(zhí)行,從而更新父組件或容器組件的 state。
placeholder:作為占位文本的字符串,用來填充第一個(gè) 標(biāo)簽。本組件中,我們將第一個(gè)選項(xiàng)的值設(shè)置成空字符串(參看下面代碼的第 10 行)。
import React from "react"; const Select = (props) => (); Select.propTypes = { name: React.PropTypes.string.isRequired, options: React.PropTypes.array.isRequired, selectedOption: React.PropTypes.string, controlFunc: React.PropTypes.func.isRequired, placeholder: React.PropTypes.string }; export default Select;
請(qǐng)注意 option 標(biāo)簽中的 key 屬性(第 14 行)。React 要求被重復(fù)操作渲染的每個(gè)元素必須擁有獨(dú)一無二的 key 值,我們這里的 .map() 方法就是所謂的重復(fù)操作。既然選擇項(xiàng)數(shù)組中的每個(gè)元素是獨(dú)有的,我們就把它們當(dāng)成 key prop。該 key 值協(xié)助 React 追蹤 DOM 變化。雖然在循環(huán)操作或 mapping 時(shí)忘加 key 屬性不會(huì)中斷應(yīng)用,但是瀏覽器的控制臺(tái)里會(huì)出現(xiàn)警告,并且渲染性能將受到影響。
以下是控制選擇框組件(記住,該組件存在于
// FormContainer.js handleAgeRangeSelect(e) { this.setState({ ownerAgeRangeSelection: e.target.value }); } // constructor 方法里別漏掉了這行: // this.handleAgeRangeSelect = this.handleAgeRangeSelect.bind(this);
讓我們深入 PropTypes 來更好地理解
CheckboxGroup.propTypes = { title: React.PropTypes.string.isRequired, type: React.PropTypes.oneOf(["checkbox", "radio"]).isRequired, setName: React.PropTypes.string.isRequired, options: React.PropTypes.array.isRequired, selectedOptions: React.PropTypes.array, controlFunc: React.PropTypes.func.isRequired };
title:一個(gè)字符串,用以填充單選或復(fù)選框集合的 label 標(biāo)簽內(nèi)容。
type:接收 "checkbox" 或 "radio" 兩種配置的一種,并用指定的配置渲染輸入框(譯注:這里指復(fù)選輸入框或單選輸入框)。
setName:一個(gè)字符串,用以填充每個(gè)單選或復(fù)選框的 name 屬性值。
options:一個(gè)由字符串元素組成的數(shù)組,數(shù)組元素用以渲染每個(gè)單選框或復(fù)選框的值和 label 的內(nèi)容。例如,["dog", "cat", "pony"] 數(shù)組中的元素將會(huì)渲染三個(gè)單選框或復(fù)選框。
selectedOptions:一個(gè)由字符串元素組成的數(shù)組,用來表示預(yù)選項(xiàng)。在示例 4 中,如果 selectedOptions 數(shù)組包含 "dog" 和 "pony" 元素,那么相應(yīng)的兩個(gè)選項(xiàng)會(huì)被渲染成選中狀態(tài),而 "cat" 選項(xiàng)則被渲染成未選中狀態(tài)。當(dāng)用戶提交表單時(shí),該數(shù)組將會(huì)是用戶的選擇數(shù)據(jù)。
controlFunc:一個(gè)方法,用來處理從 selectedOptions 數(shù)組 prop 中添加或刪除字符串的操作。
這是本表單應(yīng)用中最有趣的組件,讓我們來看一下:
import React from "react"; const CheckboxOrRadioGroup = (props) => (); CheckboxOrRadioGroup.propTypes = { title: React.PropTypes.string.isRequired, type: React.PropTypes.oneOf(["checkbox", "radio"]).isRequired, setName: React.PropTypes.string.isRequired, options: React.PropTypes.array.isRequired, selectedOptions: React.PropTypes.array, controlFunc: React.PropTypes.func.isRequired }; export default CheckboxOrRadioGroup;{props.options.map(opt => { return ( ); })}
checked={ props.selectedOptions.indexOf(option) > -1 } 這一行代碼表示單選框或復(fù)選框是否被選中的邏輯。
屬性 checked 接收一個(gè)布爾值,用來表示 input 組件是否應(yīng)該被渲染成選中狀態(tài)。我們?cè)跈z查到 input 的值是否是 props.selectedOptions 數(shù)組的元素之一時(shí)生成該布爾值。
myArray.indexOf(item) 方法返回 item 在數(shù)組中的索引值。如果 item 不在數(shù)組中,返回 -1,因此,我們寫了 > -1。
注意,0 是一個(gè)合法的索引值,所以我們需要 > -1 ,否則代碼會(huì)有 bug。如果沒有 > -1,selectedOptions 數(shù)組中的第一個(gè) item —— 其索引為 0 —— 將永遠(yuǎn)不會(huì)被渲染成選中狀態(tài),因?yàn)?0 是一個(gè)類 false 的值(譯注:在 checked 屬性中,0 會(huì)被當(dāng)成 false 處理)。
本組件的處理方法同樣比其他的有趣。
handlePetSelection(e) { const newSelection = e.target.value; let newSelectionArray; if(this.state.selectedPets.indexOf(newSelection) > -1) { newSelectionArray = this.state.selectedPets.filter(s => s !== newSelection) } else { newSelectionArray = [...this.state.selectedPets, newSelection]; } this.setState({ selectedPets: newSelectionArray }); }
如同所有處理方法一樣,事件對(duì)象被傳入方法,這樣一來我們就能拿到事件對(duì)象的值(譯注:準(zhǔn)確來說,應(yīng)該是事件目標(biāo)元素的值)。我們將該值賦給newSelection 常量。接著我們?cè)诤瘮?shù)頂部附近定義 newSelectionArray 變量。因?yàn)槲覀儗⒃谝粋€(gè) if/else 代碼塊里對(duì)該變量進(jìn)行賦值,所以用 let 而非 const 來定義它。我們?cè)诖a塊外部進(jìn)行定義,這樣一來被定義變量的作用域就是函數(shù)內(nèi)部的最外沿,并且函數(shù)內(nèi)的代碼塊都能訪問到外部定義的變量。
該方法需要處理兩種可能的情況。
如果 input 組件的值不在 selectedOptions 數(shù)組中,我們要將值添加進(jìn)該數(shù)組。
如果 input 組件的值在 selectedOptions 數(shù)組中,我們要從數(shù)組中刪除該值。
添加(第 8 - 10 行): 為了將新值添加進(jìn)選項(xiàng)數(shù)組,我們通過解構(gòu)舊數(shù)組(數(shù)組前的三點(diǎn)...表示解構(gòu))創(chuàng)建一個(gè)新數(shù)組,并且將新值添加到數(shù)組的尾部 newSelectionArray = [...this.state.selectedPets, newSelection];。
注意,我們創(chuàng)建了一個(gè)新數(shù)組,而不是通過類似 .push() 的方法來改變?cè)瓟?shù)組。不改變已存在的對(duì)象和數(shù)組,而是創(chuàng)建新的對(duì)象和數(shù)組,這在 React 中是又一個(gè)最佳實(shí)踐。開發(fā)者這樣做可以更容易地跟蹤 state 的變化,而第三方 state 管理庫,如 Redux 則可以做高性能的淺比較,而不是阻塞性能的深比較。
刪除(第 6 - 8 行):if 代碼塊借助此前用到的 .indexOf() 小技巧,檢查選項(xiàng)是否在數(shù)組中。如果選項(xiàng)已經(jīng)在數(shù)組中,通過.filter()方法,該選項(xiàng)將被移除。 該方法返回一個(gè)包含所有滿足 filter 條件的元素的新數(shù)組(記住要避免在 React 直接修改數(shù)組或?qū)ο螅。?/p>
newSelectionArray = this.state.selectedPets.filter(s => s !== newSelection)
在這種情況下,除了傳入到方法中的選項(xiàng)之外,其他選項(xiàng)都會(huì)被返回。
組件和我們已提到的那些組件非常相似,除了 resize 和 rows,目前你應(yīng)該對(duì)它的 props 很熟悉了。
TextArea.propTypes = { title: React.PropTypes.string.isRequired, rows: React.PropTypes.number.isRequired, name: React.PropTypes.string.isRequired, content: React.PropTypes.string.isRequired, resize: React.PropTypes.bool, placeholder: React.PropTypes.string, controlFunc: React.PropTypes.func.isRequired };
title:接收一個(gè)字符串,用以渲染文本域的 label 標(biāo)簽內(nèi)容。
rows:接收一個(gè)整數(shù),用來指定文本域的行數(shù)。
name:文本域的 name 屬性。
content:文本域的內(nèi)容。受控組件只會(huì)顯示通過 props 傳入的數(shù)據(jù)。
resize: 接受一個(gè)布爾值,用來指定文本域能否調(diào)整大小。
placeholder:充當(dāng)文本域占位文本的字符串。
controlFunc: 它是從父組件或容器組件傳下來的方法。因?yàn)樵摲椒⊕燧d在 React 的 onChange 處理方法上,所以每當(dāng)改變選擇框組件的值時(shí),該方法都會(huì)被執(zhí)行,從而更新父組件或容器組件的 state。
組件的完整代碼:
import React from "react"; const TextArea = (props) => (); TextArea.propTypes = { title: React.PropTypes.string.isRequired, rows: React.PropTypes.number.isRequired, name: React.PropTypes.string.isRequired, content: React.PropTypes.string.isRequired, resize: React.PropTypes.bool, placeholder: React.PropTypes.string, controlFunc: React.PropTypes.func.isRequired }; export default TextArea;
handleClearForm 和 handleFormSubmit 方法操作整個(gè)表單。
1. handleClearForm既然我們?cè)诒韱蔚母魈幎际褂昧藛蜗驍?shù)據(jù)流,那么清除表單數(shù)據(jù)對(duì)我們來說也是小菜一碟。
清除表單子組件中顯示的數(shù)據(jù)很簡(jiǎn)單,只要把容器的 state (譯注:這里是指 state 對(duì)象上掛載的各個(gè)變量)設(shè)置成空數(shù)組和空字符串就可以了(如果有數(shù)字輸入框的話則是將值設(shè)置成 0)。
handleClearForm(e) { e.preventDefault(); this.setState({ ownerName: "", selectedPets: [], ownerAgeRangeSelection: "", siblingSelection: [], currentPetCount: 0, description: "" }); }
注意,e.preventDefault() 阻止了頁面重新加載,接著 setState() 方法用來清除表單數(shù)據(jù)。
2. handleFormSubmit為了提交表單數(shù)據(jù),我們從 state 中抽取需要提交的屬性值,創(chuàng)建了一個(gè)對(duì)象。接著使用 AJAX 庫或技術(shù)將這些數(shù)據(jù)發(fā)送給 API(本文不包含此類內(nèi)容)。
handleFormSubmit(e) { e.preventDefault(); const formPayload = { ownerName: this.state.ownerName, selectedPets: this.state.selectedPets, ownerAgeRangeSelection: this.state.ownerAgeRangeSelection, siblingSelection: this.state.siblingSelection, currentPetCount: this.state.currentPetCount, description: this.state.description }; console.log("Send this in a POST request:", formPayload); this.handleClearForm(e); }
請(qǐng)注意我們?cè)谔峤粩?shù)據(jù)后執(zhí)行 this.handleClearForm(e) 清除了表單。
表單校驗(yàn)受控表單組件非常適合自定義表單校驗(yàn)。假設(shè)要從 組件中排除字母 "e",可以這樣做:
handleDescriptionChange(e) { const textArray = e.target.value.split("").filter(x => x !== "e"); console.log("string split into array of letters",textArray); const filteredText = textArray.join(""); this.setState({ description: filteredText }); }
把 e.target.value 字符串分割成字母數(shù)組,就生成了上述的 textArray。這樣字母 “e” (或其他設(shè)法排除的字母)就被過濾掉了。再把剩余的字母組成的數(shù)組拼成字符串,最后用該新字符串去設(shè)置組件 state。還不錯(cuò)吧?
以上代碼放在本文的倉庫中,但我將它們注釋掉了,你可以按自己的需求自由地調(diào)整。
下面是我承諾給你們的
import React, {Component} from "react"; import CheckboxOrRadioGroup from "../components/CheckboxOrRadioGroup"; import SingleInput from "../components/SingleInput"; import TextArea from "../components/TextArea"; import Select from "../components/Select"; class FormContainer extends Component { constructor(props) { super(props); this.state = { ownerName: "", petSelections: [], selectedPets: [], ageOptions: [], ownerAgeRangeSelection: "", siblingOptions: [], siblingSelection: [], currentPetCount: 0, description: "" }; this.handleFormSubmit = this.handleFormSubmit.bind(this); this.handleClearForm = this.handleClearForm.bind(this); this.handleFullNameChange = this.handleFullNameChange.bind(this); this.handleCurrentPetCountChange = this.handleCurrentPetCountChange.bind(this); this.handleAgeRangeSelect = this.handleAgeRangeSelect.bind(this); this.handlePetSelection = this.handlePetSelection.bind(this); this.handleSiblingsSelection = this.handleSiblingsSelection.bind(this); this.handleDescriptionChange = this.handleDescriptionChange.bind(this); } componentDidMount() { // 模擬請(qǐng)求用戶數(shù)據(jù) //(create-react-app 構(gòu)建配置里包含了 fetch 的 polyfill) fetch("./fake_db.json") .then(res => res.json()) .then(data => { this.setState({ ownerName: data.ownerName, petSelections: data.petSelections, selectedPets: data.selectedPets, ageOptions: data.ageOptions, ownerAgeRangeSelection: data.ownerAgeRangeSelection, siblingOptions: data.siblingOptions, siblingSelection: data.siblingSelection, currentPetCount: data.currentPetCount, description: data.description }); }); } handleFullNameChange(e) { this.setState({ ownerName: e.target.value }); } handleCurrentPetCountChange(e) { this.setState({ currentPetCount: e.target.value }); } handleAgeRangeSelect(e) { this.setState({ ownerAgeRangeSelection: e.target.value }); } handlePetSelection(e) { const newSelection = e.target.value; let newSelectionArray; if(this.state.selectedPets.indexOf(newSelection) > -1) { newSelectionArray = this.state.selectedPets.filter(s => s !== newSelection) } else { newSelectionArray = [...this.state.selectedPets, newSelection]; } this.setState({ selectedPets: newSelectionArray }); } handleSiblingsSelection(e) { this.setState({ siblingSelection: [e.target.value] }); } handleDescriptionChange(e) { this.setState({ description: e.target.value }); } handleClearForm(e) { e.preventDefault(); this.setState({ ownerName: "", selectedPets: [], ownerAgeRangeSelection: "", siblingSelection: [], currentPetCount: 0, description: "" }); } handleFormSubmit(e) { e.preventDefault(); const formPayload = { ownerName: this.state.ownerName, selectedPets: this.state.selectedPets, ownerAgeRangeSelection: this.state.ownerAgeRangeSelection, siblingSelection: this.state.siblingSelection, currentPetCount: this.state.currentPetCount, description: this.state.description }; console.log("Send this in a POST request:", formPayload) this.handleClearForm(e); } render() { return (); } } export default FormContainer; 總結(jié)
我承認(rèn)用 React 構(gòu)建受控表單組件要做一些重復(fù)勞動(dòng)(比如容器組件中的處理方法),但就你對(duì)應(yīng)用的掌控度和 state 變更的透明度來說,預(yù)先投入精力是超值的。你的代碼會(huì)變得可維護(hù)并且很高效。
如果想在我發(fā)布新文章時(shí)接到通知,你可以在博客的導(dǎo)航欄部分注冊(cè)我的郵件發(fā)送清單。
iKcamp原創(chuàng)新書《移動(dòng)Web前端高效開發(fā)實(shí)戰(zhàn)》已在亞馬遜、京東、當(dāng)當(dāng)開售。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/91743.html
摘要:函數(shù)更新屬性,進(jìn)而更新元素的值。由于箭頭函數(shù)存在于父組件中,所以中的指向父組件。一旦表單被提交,的值就被設(shè)置為。遺憾的是,沒有節(jié)點(diǎn)是包含了集合的。在這種情況下,這個(gè)節(jié)點(diǎn)列表包含三個(gè)節(jié)點(diǎn)和被選中的值。 原文地址:React Forms: Using Refs 原文作者:Loren Stewart 譯者:萌萌 校對(duì)者:小 boy React 提供了兩種從 元素中獲取值的標(biāo)準(zhǔn)方法。第一...
摘要:前端日?qǐng)?bào)精選中的垃圾收集,圖文指南十個(gè)免費(fèi)的前端開發(fā)工具專題之遞歸如何在鏈中共享變量基于的爬蟲框架中文譯十六進(jìn)制顏色揭秘掘金掘金小書基本環(huán)境安裝小書教程中間件對(duì)閉包的一個(gè)巧妙使用簡(jiǎn)書源碼分析掘金組件開發(fā)練習(xí)焦點(diǎn)圖切換前端學(xué) 2017-09-13 前端日?qǐng)?bào) 精選 V8 中的垃圾收集(GC),圖文指南十個(gè)免費(fèi)的web前端開發(fā)工具JavaScript專題之遞歸 · Issue #49 · m...
2017-07-28 前端日?qǐng)?bào) 精選 React的新引擎—React Fiber是什么?Chromeless 讓 Chrome 自動(dòng)化變得簡(jiǎn)單【譯】JavaScript屬性名稱中的隱藏信息前端測(cè)試框架 JestES6中的JavaScript工廠函數(shù)Why Composition is Harder with ClassesGET READY: A NEW V8 IS COMING, NODE.JS...
摘要:首次發(fā)表在個(gè)人博客受控組件或都要綁定一個(gè)事件每當(dāng)表單的狀態(tài)發(fā)生變化都會(huì)被寫入組件的中這種組件在中被稱為受控組件在受控組件中組件渲染出的狀態(tài)與它的或者向?qū)?yīng)通過這種方式消除了組件的局部狀態(tài)是的應(yīng)用的整個(gè)狀態(tài)可控官方同樣推薦使用受控表單組件總結(jié) 首次發(fā)表在個(gè)人博客 受控組件 { this.setState({ value: e.target.val...
摘要:假如我們從后臺(tái)拉取一個(gè)數(shù)據(jù)要填入輸入框,那么必須得使用受控組件,因?yàn)榉鞘芸亟M件只能被用戶輸入。不影響正常輸入填充該輸入框的默認(rèn)值,此時(shí)不顯示內(nèi)容。 網(wǎng)頁中使用的form表單大家肯定都再熟悉不過了,它主要作用是用來收集和提交信息。React中的表單組件與我們普通的Html中的表單及其表現(xiàn)形式?jīng)]有什么不同,所以如何使用表單我覺得再拿出來說可能是畫蛇添足、毫無意義。不過再怎么樣也不能辜負(fù)大家...
閱讀 2627·2021-11-23 09:51
閱讀 860·2021-09-24 10:37
閱讀 3612·2021-09-02 15:15
閱讀 1962·2019-08-30 13:03
閱讀 1881·2019-08-29 15:41
閱讀 2624·2019-08-29 14:12
閱讀 1424·2019-08-29 11:19
閱讀 3301·2019-08-26 13:39