[React 基础系列] 受控表单 vs 不受控表单
[React 基礎(chǔ)系列] 受控表單 vs 不受控表單
- 受控表單
- refs
- 不受控表單
- 不受控組件
- 總結(jié)
之前的學(xué)習(xí)部分帶了一些表單內(nèi)容的使用——之前的案例基本上是用的都是 input,接下來就學(xué)習(xí)一下受控表單和不受控表單之間的區(qū)別,并且通過非受控表單了解一下非受控組件的知識點。
受控表單指的是狀態(tài)由 React 內(nèi)部進行管理的表單,自然,不受控表單值得就是狀態(tài)不由 React 內(nèi)部進行管理的表單。
學(xué)習(xí)案例下載資源在:受控表單 vs 不受控表單-案例
前復(fù)習(xí)過的內(nèi)容:
- 什么是 JSX,以及如何使用 JSX
- 元素 vs 組件
- 狀態(tài) & 狀態(tài)更新 & 生命周期方法
- 事件處理
受控表單
受控表單指的是所有的表單狀態(tài)由 state 進行管理的表單,通過 setState 觸發(fā)狀態(tài)更新,如下面的這個受控組件:
class ControlledForm extends Component {constructor() {super();this.state = {name: '',phone: '',};this.onSubmit = this.onSubmit.bind(this);}updateInputHandler = (e, label) => {this.setState((prevState) => {return { ...prevState, [label]: e.target.value };});};onSubmit = (e) => {for (const [key, val] of Object.entries(this.state)) {console.log(key, val);}// e.preventDefault(); 放置頁面的重定向e.preventDefault();};render() {return (<form onSubmit={this.onSubmit}><div><label>name: </label><inputtype="text"value={this.state.name}onChange={(e) => this.updateInputHandler(e, 'name')}/></div><div><label>phone: </label><inputtype="text"value={this.state.phone}onChange={(e) => this.updateInputHandler(e, 'phone')}/></div><div><input type="submit" value="submit" /></div></form>);} }實現(xiàn)效果為:
這里的事件處理通過接收另外一個參數(shù),可以做到簡化狀態(tài)更新的方法。這是利用了 ES6 中的計算屬性名的特殊特性去實現(xiàn)的。通過使用 obj[variable] 這種語法可以通過傳入?yún)?shù)(variable),做到動態(tài)更新參數(shù)(variable)的值。
更懂 ES6 的新特性可以參考: 都 2021 年了還不會連 ES6/ES2015 更新了什么都不知道吧 這篇筆記。
另外,注意到這里的 setState 的寫法與之前的案例不一樣,這是因為 React 更新狀態(tài)并不能保證是同步地情況。為了節(jié)省效率,它內(nèi)部會判斷哪些 setState 是可以合并,放在一個 batch job 里面去更新。所以直接在 setState 調(diào)用 this.state 去傳值是一個非常危險的行為。而通過 this.setState(prevState => {//...}) 回調(diào)函數(shù),能夠保證在 setState 內(nèi)獲取的狀態(tài),是更新時的狀態(tài)。
#mermaid-svg-LDPy5DrdGUnkQthS .label{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);fill:#333;color:#333}#mermaid-svg-LDPy5DrdGUnkQthS .label text{fill:#333}#mermaid-svg-LDPy5DrdGUnkQthS .node rect,#mermaid-svg-LDPy5DrdGUnkQthS .node circle,#mermaid-svg-LDPy5DrdGUnkQthS .node ellipse,#mermaid-svg-LDPy5DrdGUnkQthS .node polygon,#mermaid-svg-LDPy5DrdGUnkQthS .node path{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-LDPy5DrdGUnkQthS .node .label{text-align:center;fill:#333}#mermaid-svg-LDPy5DrdGUnkQthS .node.clickable{cursor:pointer}#mermaid-svg-LDPy5DrdGUnkQthS .arrowheadPath{fill:#333}#mermaid-svg-LDPy5DrdGUnkQthS .edgePath .path{stroke:#333;stroke-width:1.5px}#mermaid-svg-LDPy5DrdGUnkQthS .flowchart-link{stroke:#333;fill:none}#mermaid-svg-LDPy5DrdGUnkQthS .edgeLabel{background-color:#e8e8e8;text-align:center}#mermaid-svg-LDPy5DrdGUnkQthS .edgeLabel rect{opacity:0.9}#mermaid-svg-LDPy5DrdGUnkQthS .edgeLabel span{color:#333}#mermaid-svg-LDPy5DrdGUnkQthS .cluster rect{fill:#ffffde;stroke:#aa3;stroke-width:1px}#mermaid-svg-LDPy5DrdGUnkQthS .cluster text{fill:#333}#mermaid-svg-LDPy5DrdGUnkQthS div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:12px;background:#ffffde;border:1px solid #aa3;border-radius:2px;pointer-events:none;z-index:100}#mermaid-svg-LDPy5DrdGUnkQthS .actor{stroke:#ccf;fill:#ECECFF}#mermaid-svg-LDPy5DrdGUnkQthS text.actor>tspan{fill:#000;stroke:none}#mermaid-svg-LDPy5DrdGUnkQthS .actor-line{stroke:grey}#mermaid-svg-LDPy5DrdGUnkQthS .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333}#mermaid-svg-LDPy5DrdGUnkQthS .messageLine1{stroke-width:1.5;stroke-dasharray:2, 2;stroke:#333}#mermaid-svg-LDPy5DrdGUnkQthS #arrowhead path{fill:#333;stroke:#333}#mermaid-svg-LDPy5DrdGUnkQthS .sequenceNumber{fill:#fff}#mermaid-svg-LDPy5DrdGUnkQthS #sequencenumber{fill:#333}#mermaid-svg-LDPy5DrdGUnkQthS #crosshead path{fill:#333;stroke:#333}#mermaid-svg-LDPy5DrdGUnkQthS .messageText{fill:#333;stroke:#333}#mermaid-svg-LDPy5DrdGUnkQthS .labelBox{stroke:#ccf;fill:#ECECFF}#mermaid-svg-LDPy5DrdGUnkQthS .labelText,#mermaid-svg-LDPy5DrdGUnkQthS .labelText>tspan{fill:#000;stroke:none}#mermaid-svg-LDPy5DrdGUnkQthS .loopText,#mermaid-svg-LDPy5DrdGUnkQthS .loopText>tspan{fill:#000;stroke:none}#mermaid-svg-LDPy5DrdGUnkQthS .loopLine{stroke-width:2px;stroke-dasharray:2, 2;stroke:#ccf;fill:#ccf}#mermaid-svg-LDPy5DrdGUnkQthS .note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-LDPy5DrdGUnkQthS .noteText,#mermaid-svg-LDPy5DrdGUnkQthS .noteText>tspan{fill:#000;stroke:none}#mermaid-svg-LDPy5DrdGUnkQthS .activation0{fill:#f4f4f4;stroke:#666}#mermaid-svg-LDPy5DrdGUnkQthS .activation1{fill:#f4f4f4;stroke:#666}#mermaid-svg-LDPy5DrdGUnkQthS .activation2{fill:#f4f4f4;stroke:#666}#mermaid-svg-LDPy5DrdGUnkQthS .mermaid-main-font{font-family:"trebuchet ms", verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-LDPy5DrdGUnkQthS .section{stroke:none;opacity:0.2}#mermaid-svg-LDPy5DrdGUnkQthS .section0{fill:rgba(102,102,255,0.49)}#mermaid-svg-LDPy5DrdGUnkQthS .section2{fill:#fff400}#mermaid-svg-LDPy5DrdGUnkQthS .section1,#mermaid-svg-LDPy5DrdGUnkQthS .section3{fill:#fff;opacity:0.2}#mermaid-svg-LDPy5DrdGUnkQthS .sectionTitle0{fill:#333}#mermaid-svg-LDPy5DrdGUnkQthS .sectionTitle1{fill:#333}#mermaid-svg-LDPy5DrdGUnkQthS .sectionTitle2{fill:#333}#mermaid-svg-LDPy5DrdGUnkQthS .sectionTitle3{fill:#333}#mermaid-svg-LDPy5DrdGUnkQthS .sectionTitle{text-anchor:start;font-size:11px;text-height:14px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-LDPy5DrdGUnkQthS .grid .tick{stroke:#d3d3d3;opacity:0.8;shape-rendering:crispEdges}#mermaid-svg-LDPy5DrdGUnkQthS .grid .tick text{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-LDPy5DrdGUnkQthS .grid path{stroke-width:0}#mermaid-svg-LDPy5DrdGUnkQthS .today{fill:none;stroke:red;stroke-width:2px}#mermaid-svg-LDPy5DrdGUnkQthS .task{stroke-width:2}#mermaid-svg-LDPy5DrdGUnkQthS .taskText{text-anchor:middle;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-LDPy5DrdGUnkQthS .taskText:not([font-size]){font-size:11px}#mermaid-svg-LDPy5DrdGUnkQthS .taskTextOutsideRight{fill:#000;text-anchor:start;font-size:11px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-LDPy5DrdGUnkQthS .taskTextOutsideLeft{fill:#000;text-anchor:end;font-size:11px}#mermaid-svg-LDPy5DrdGUnkQthS .task.clickable{cursor:pointer}#mermaid-svg-LDPy5DrdGUnkQthS .taskText.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-LDPy5DrdGUnkQthS .taskTextOutsideLeft.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-LDPy5DrdGUnkQthS .taskTextOutsideRight.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-LDPy5DrdGUnkQthS .taskText0,#mermaid-svg-LDPy5DrdGUnkQthS .taskText1,#mermaid-svg-LDPy5DrdGUnkQthS .taskText2,#mermaid-svg-LDPy5DrdGUnkQthS .taskText3{fill:#fff}#mermaid-svg-LDPy5DrdGUnkQthS .task0,#mermaid-svg-LDPy5DrdGUnkQthS .task1,#mermaid-svg-LDPy5DrdGUnkQthS .task2,#mermaid-svg-LDPy5DrdGUnkQthS .task3{fill:#8a90dd;stroke:#534fbc}#mermaid-svg-LDPy5DrdGUnkQthS .taskTextOutside0,#mermaid-svg-LDPy5DrdGUnkQthS .taskTextOutside2{fill:#000}#mermaid-svg-LDPy5DrdGUnkQthS .taskTextOutside1,#mermaid-svg-LDPy5DrdGUnkQthS .taskTextOutside3{fill:#000}#mermaid-svg-LDPy5DrdGUnkQthS .active0,#mermaid-svg-LDPy5DrdGUnkQthS .active1,#mermaid-svg-LDPy5DrdGUnkQthS .active2,#mermaid-svg-LDPy5DrdGUnkQthS .active3{fill:#bfc7ff;stroke:#534fbc}#mermaid-svg-LDPy5DrdGUnkQthS .activeText0,#mermaid-svg-LDPy5DrdGUnkQthS .activeText1,#mermaid-svg-LDPy5DrdGUnkQthS .activeText2,#mermaid-svg-LDPy5DrdGUnkQthS .activeText3{fill:#000 !important}#mermaid-svg-LDPy5DrdGUnkQthS .done0,#mermaid-svg-LDPy5DrdGUnkQthS .done1,#mermaid-svg-LDPy5DrdGUnkQthS .done2,#mermaid-svg-LDPy5DrdGUnkQthS .done3{stroke:grey;fill:#d3d3d3;stroke-width:2}#mermaid-svg-LDPy5DrdGUnkQthS .doneText0,#mermaid-svg-LDPy5DrdGUnkQthS .doneText1,#mermaid-svg-LDPy5DrdGUnkQthS .doneText2,#mermaid-svg-LDPy5DrdGUnkQthS .doneText3{fill:#000 !important}#mermaid-svg-LDPy5DrdGUnkQthS .crit0,#mermaid-svg-LDPy5DrdGUnkQthS .crit1,#mermaid-svg-LDPy5DrdGUnkQthS .crit2,#mermaid-svg-LDPy5DrdGUnkQthS .crit3{stroke:#f88;fill:red;stroke-width:2}#mermaid-svg-LDPy5DrdGUnkQthS .activeCrit0,#mermaid-svg-LDPy5DrdGUnkQthS .activeCrit1,#mermaid-svg-LDPy5DrdGUnkQthS .activeCrit2,#mermaid-svg-LDPy5DrdGUnkQthS .activeCrit3{stroke:#f88;fill:#bfc7ff;stroke-width:2}#mermaid-svg-LDPy5DrdGUnkQthS .doneCrit0,#mermaid-svg-LDPy5DrdGUnkQthS .doneCrit1,#mermaid-svg-LDPy5DrdGUnkQthS .doneCrit2,#mermaid-svg-LDPy5DrdGUnkQthS .doneCrit3{stroke:#f88;fill:#d3d3d3;stroke-width:2;cursor:pointer;shape-rendering:crispEdges}#mermaid-svg-LDPy5DrdGUnkQthS .milestone{transform:rotate(45deg) scale(0.8, 0.8)}#mermaid-svg-LDPy5DrdGUnkQthS .milestoneText{font-style:italic}#mermaid-svg-LDPy5DrdGUnkQthS .doneCritText0,#mermaid-svg-LDPy5DrdGUnkQthS .doneCritText1,#mermaid-svg-LDPy5DrdGUnkQthS .doneCritText2,#mermaid-svg-LDPy5DrdGUnkQthS .doneCritText3{fill:#000 !important}#mermaid-svg-LDPy5DrdGUnkQthS .activeCritText0,#mermaid-svg-LDPy5DrdGUnkQthS .activeCritText1,#mermaid-svg-LDPy5DrdGUnkQthS .activeCritText2,#mermaid-svg-LDPy5DrdGUnkQthS .activeCritText3{fill:#000 !important}#mermaid-svg-LDPy5DrdGUnkQthS .titleText{text-anchor:middle;font-size:18px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-LDPy5DrdGUnkQthS g.classGroup text{fill:#9370db;stroke:none;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:10px}#mermaid-svg-LDPy5DrdGUnkQthS g.classGroup text .title{font-weight:bolder}#mermaid-svg-LDPy5DrdGUnkQthS g.clickable{cursor:pointer}#mermaid-svg-LDPy5DrdGUnkQthS g.classGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-LDPy5DrdGUnkQthS g.classGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-LDPy5DrdGUnkQthS .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5}#mermaid-svg-LDPy5DrdGUnkQthS .classLabel .label{fill:#9370db;font-size:10px}#mermaid-svg-LDPy5DrdGUnkQthS .relation{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-LDPy5DrdGUnkQthS .dashed-line{stroke-dasharray:3}#mermaid-svg-LDPy5DrdGUnkQthS #compositionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-LDPy5DrdGUnkQthS #compositionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-LDPy5DrdGUnkQthS #aggregationStart{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-LDPy5DrdGUnkQthS #aggregationEnd{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-LDPy5DrdGUnkQthS #dependencyStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-LDPy5DrdGUnkQthS #dependencyEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-LDPy5DrdGUnkQthS #extensionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-LDPy5DrdGUnkQthS #extensionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-LDPy5DrdGUnkQthS .commit-id,#mermaid-svg-LDPy5DrdGUnkQthS .commit-msg,#mermaid-svg-LDPy5DrdGUnkQthS .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-LDPy5DrdGUnkQthS .pieTitleText{text-anchor:middle;font-size:25px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-LDPy5DrdGUnkQthS .slice{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-LDPy5DrdGUnkQthS g.stateGroup text{fill:#9370db;stroke:none;font-size:10px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-LDPy5DrdGUnkQthS g.stateGroup text{fill:#9370db;fill:#333;stroke:none;font-size:10px}#mermaid-svg-LDPy5DrdGUnkQthS g.statediagram-cluster .cluster-label text{fill:#333}#mermaid-svg-LDPy5DrdGUnkQthS g.stateGroup .state-title{font-weight:bolder;fill:#000}#mermaid-svg-LDPy5DrdGUnkQthS g.stateGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-LDPy5DrdGUnkQthS g.stateGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-LDPy5DrdGUnkQthS .transition{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-LDPy5DrdGUnkQthS .stateGroup .composit{fill:white;border-bottom:1px}#mermaid-svg-LDPy5DrdGUnkQthS .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px}#mermaid-svg-LDPy5DrdGUnkQthS .state-note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-LDPy5DrdGUnkQthS .state-note text{fill:black;stroke:none;font-size:10px}#mermaid-svg-LDPy5DrdGUnkQthS .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.7}#mermaid-svg-LDPy5DrdGUnkQthS .edgeLabel text{fill:#333}#mermaid-svg-LDPy5DrdGUnkQthS .stateLabel text{fill:#000;font-size:10px;font-weight:bold;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-LDPy5DrdGUnkQthS .node circle.state-start{fill:black;stroke:black}#mermaid-svg-LDPy5DrdGUnkQthS .node circle.state-end{fill:black;stroke:white;stroke-width:1.5}#mermaid-svg-LDPy5DrdGUnkQthS #statediagram-barbEnd{fill:#9370db}#mermaid-svg-LDPy5DrdGUnkQthS .statediagram-cluster rect{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-LDPy5DrdGUnkQthS .statediagram-cluster rect.outer{rx:5px;ry:5px}#mermaid-svg-LDPy5DrdGUnkQthS .statediagram-state .divider{stroke:#9370db}#mermaid-svg-LDPy5DrdGUnkQthS .statediagram-state .title-state{rx:5px;ry:5px}#mermaid-svg-LDPy5DrdGUnkQthS .statediagram-cluster.statediagram-cluster .inner{fill:white}#mermaid-svg-LDPy5DrdGUnkQthS .statediagram-cluster.statediagram-cluster-alt .inner{fill:#e0e0e0}#mermaid-svg-LDPy5DrdGUnkQthS .statediagram-cluster .inner{rx:0;ry:0}#mermaid-svg-LDPy5DrdGUnkQthS .statediagram-state rect.basic{rx:5px;ry:5px}#mermaid-svg-LDPy5DrdGUnkQthS .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#efefef}#mermaid-svg-LDPy5DrdGUnkQthS .note-edge{stroke-dasharray:5}#mermaid-svg-LDPy5DrdGUnkQthS .statediagram-note rect{fill:#fff5ad;stroke:#aa3;stroke-width:1px;rx:0;ry:0}:root{--mermaid-font-family: '"trebuchet ms", verdana, arial';--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive}#mermaid-svg-LDPy5DrdGUnkQthS .error-icon{fill:#522}#mermaid-svg-LDPy5DrdGUnkQthS .error-text{fill:#522;stroke:#522}#mermaid-svg-LDPy5DrdGUnkQthS .edge-thickness-normal{stroke-width:2px}#mermaid-svg-LDPy5DrdGUnkQthS .edge-thickness-thick{stroke-width:3.5px}#mermaid-svg-LDPy5DrdGUnkQthS .edge-pattern-solid{stroke-dasharray:0}#mermaid-svg-LDPy5DrdGUnkQthS .edge-pattern-dashed{stroke-dasharray:3}#mermaid-svg-LDPy5DrdGUnkQthS .edge-pattern-dotted{stroke-dasharray:2}#mermaid-svg-LDPy5DrdGUnkQthS .marker{fill:#333}#mermaid-svg-LDPy5DrdGUnkQthS .marker.cross{stroke:#333}:root { --mermaid-font-family: "trebuchet ms", verdana, arial;} #mermaid-svg-LDPy5DrdGUnkQthS {color: rgba(0, 0, 0, 0.75);font: ;} 未執(zhí)行 未執(zhí)行 未執(zhí)行 未執(zhí)行 執(zhí)行,順序不確定 執(zhí)行,順序不確定 執(zhí)行,順序不確定 執(zhí)行,順序不確定 setState1 setState1 setState2 setState2 setState3 setState3 setState4 setState4 batch Job按照上面的圖示所說,在 setState2 中調(diào)用的this.state,極大可能會受到 setState4 的影響,從而造成更新的狀態(tài)出錯。這種合并更新的情況在大型應(yīng)用中經(jīng)常會發(fā)生,所以必須要注意這點。
確實受控組件寫起來會有點麻煩,尤其是之后如果需要加其他的類型檢查,那么 updateInputHandler 里面的內(nèi)容會變得非常的多,這也是下一步會實現(xiàn)優(yōu)化/封裝的內(nèi)容題材。
refs
refs 其實是一種可以在 React 中更直接訪問 DOM 節(jié)點,或在 render 方法中創(chuàng)建 React 元素的方法。它的出現(xiàn)是針對于在組件中可能需要在非常規(guī)操作的 React 時所實用的方法。
回顧一下,常規(guī)方法即組件內(nèi)通過 state 管理,父子組件通過 props 傳遞信息。自然,非常規(guī)方法就是不通過 state 也不通過 props 去對組件 和/或 元素進行操作。
React 官方其實是不太推薦使用 refs 去進行 DOM 的操作,因為這會放棄 Virtual DOM 帶來的好處——即通過對比虛擬 DOM 樹和真實 DOM 樹,只重新渲染更新過的 DOM 節(jié)點,這樣可以省去大量無意義的重復(fù)渲染。
React 團隊列舉出了 3 種使用 refs 的情景:
- 管理焦點,文本選擇或媒體播放。
- 觸發(fā)強制動畫。
- 集成第三方 DOM 庫。
一般來說,在常規(guī)的業(yè)務(wù)情況下都不太需要用到 refs……至少我到現(xiàn)在沒用過。現(xiàn)在創(chuàng)建和使用 refs 的方法也很簡單:
class MyComponent extends React.Component {constructor(props) {super(props);// 通過 createRef 創(chuàng)建refthis.myRef = React.createRef();}render() {// 通過 ref={this.{創(chuàng)建的ref實例}} 就能夠關(guān)聯(lián)refreturn <div className="exposeRef" ref={this.myRef} />;} }這樣,類名為 exposeRef 的 div 元素就可以通過操作 this.myRef 的方法去修改。畢竟,refs 也可以通過 props 傳遞給其他的組件,這樣就能夠在其他的組件——通常情況下是 MyComponent 的子組件——中直接操作 exposeRef。
不受控表單
不受控表單的內(nèi)容即然無法由 state 控制,那么取值就無法通過 state 去獲取了。這種情況下,也只能交給 refs 去處理了,如:
class Form extends Component {constructor() {super();this.name = React.createRef();this.phone = React.createRef();this.onSubmit = this.onSubmit.bind(this);}onSubmit(e) {console.log('submit form');console.log(this.name.current.value, this.phone.current.value);// e.preventDefault(); 放置頁面的重定向e.preventDefault();}render() {return (<form onSubmit={this.onSubmit}><div><input type="text" ref={this.name} /></div><div><input type="text" ref={this.phone} /></div><div><input type="submit" value="submit" /></div></form>);} }使用效果為:
可以看到第一行的 submit form,以及第二行也成功輸出了兩個 input 輸入框中的值。
如果只需要表單的值,并不需要對表單的內(nèi)容進行驗證,使用不受控表單會方便一些,通過對比同樣的代碼也能看到,非受控組件的代碼量少一些,實現(xiàn)也更簡單一些。
相對而言,這種業(yè)務(wù)的應(yīng)用范圍也相對較少。
注意,還記得 狀態(tài) & 狀態(tài)更新 & 生命周期方法 中提到的報錯信息嗎:
其中將 input 中的 value 改成 defaultValue 這個解決方案,主要針對的就是非受控組件而進行的提議。在非受控組件中,可以通過添加 defaultValue 這個屬性去為其設(shè)置默認(rèn)值。
不受控組件
不受控表單是一種不受控組件,但是不受控組件的應(yīng)用范圍更廣一些。
相較于受控組間,不受控組件的使用情況比較少,大多數(shù)情況下都會使用到第三方庫去對 div 進行管理,如使用一些可視化處理的庫,這種情況下也需要搭配 componentWillUnmount 方法去清理由第三方庫管理的元素。
例如說 How to properly use componentWillUnmount() in ReactJs 中被采納的答案就使用了一個案例:
import React from 'react'; import { Component } from 'react'; import ReactDom from 'react-dom'; import d3Chart from './d3charts';export default class Chart extends Component {static propTypes = {data: React.PropTypes.array,domain: React.PropTypes.object,};constructor(props) {super(props);}componentDidMount() {let el = ReactDom.findDOMNode(this);d3Chart.create(el,{width: '100%',height: '300px',},this.getChartState());}componentDidUpdate() {let el = ReactDom.findDOMNode(this);d3Chart.update(el, this.getChartState());}getChartState() {return {data: this.props.data,domain: this.props.domain,};}componentWillUnmount() {let el = ReactDom.findDOMNode(this);d3Chart.destroy(el);}render() {return <div className="Chart"></div>;} }這個案例中的 Chart 組件就不包含任何的狀態(tài),對圖像進行的任何操作,都是由 d3Chart 本身去進行的狀態(tài)管理。
另外,findDOMNode 這個函數(shù)在嚴(yán)格模式下,也就是 <React.StrictMode><其他組件 /></React.StrictMode> 下已經(jīng)被廢棄使用,并且官方建議使用 refs 代替 findDOMNode。
在使用第三方組件的時候一定要記得,如果在 componentDidMount 中有通過綁定 ref/findDOMNode 去創(chuàng)建新對象的情況,那么在 componentWillUnmount 一定要注意去銷毀創(chuàng)建的對象,以防內(nèi)存泄露的情況。
總結(jié)
這里主要就表單的內(nèi)容進行了一定程度的深入了解,并且就非受控表單學(xué)習(xí)了 refs 的使用,以及在 React 中集成第三方庫管理非受控組件需要注意的要點。
總結(jié)知識點如下:
-
受控表單通過 state 去進行狀態(tài)管理
受控表單中的知識點包括:
-
ES6 的計算屬性
通過計算屬性可以快速更新對象給定參數(shù)的值
-
正確的使用 setState
這里指代的內(nèi)容,失去去更新有多個鍵值對的狀態(tài)。
為了性能的提升,React 存在壓縮 setState,然后使用 batch update 去更新多個 setState,從而避免頻繁的 UI 更新。這個時候,就要采取另外的寫法去更新 etState,而不能通過直接調(diào)用 this.state 的方法去取值
-
-
非受控表單,讓頁面自己去處理值更新的問題
通過 refs 去更新和獲取值
-
非受控組件,包含非受控表單,應(yīng)用范圍更廣
采用了 StackOverflow 的一個案例,去學(xué)習(xí)非受控組件的應(yīng)用
總結(jié)
以上是生活随笔為你收集整理的[React 基础系列] 受控表单 vs 不受控表单的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vue-qq 实践(一)
- 下一篇: 简单静态路由解析