從 0 到 1 實現 react - onChange 事件以及受控組
該系列文章在實現 cpreact 的同時理順 React 框架的核心內容
從一個疑問點開始
接上一章 丟擲的問題 ———— react 中的 onChange 事件和原生 DOM 事件中的 onchange 表現不一致,舉例說明如下:
// React 中的 onChange 事件class App extends Component { constructor(props) { super(props) this.onChange = this.onChange.bind(this) } onChange(e) { console.log('鍵盤松開立刻執行') } render() { return ( ) } }/*--------------分割線---------------*/// 原生 DOM 事件中的 onchange 事件:document.getElementById('test').addEventListener('change', (e) => { console.log('鍵盤松開以後還需按下Enter鍵或者點下滑鼠才會觸發') })
撥雲見霧
我們來看下 React 的一個 issue 。有兩點資訊和這篇文章的話題相關。
Drastically simplify the event system
Migrate from onChange to onInput and don’t polyfill it for uncontrolled components
從這兩點內容我們可以得知下面的資訊:
React 實現了一套,也就是它的事件機制和原生事件間會有不同。比如它目前 onChange 事件其實對應著原生事件中的 input 事件。在這個 issue 中明確了未來會使用 onInput 事件替代 onChange 事件,並且會大幅度地簡化合成事件。
有了以上資訊後,我們對 onChange 事件(將來的 onInput 事件)的程式碼作如下更改:
function setAttribute(dom, attr, value) { ... if (attr.match(/onw+/)) { // 處理事件的屬性: let eventName = attr.toLowerCase().substr(2) if (eventName === 'change') { eventName = 'input' } // 和現階段的 react 統一 dom.addEventListener(eventName, value) } ... }
自由元件以及受控元件
區分自由元件以及受控元件在於表單的值是否由 value
這個屬性控制,比較如下程式碼:
const case1 = () => // 此時輸入框內可以隨意增減任意值const case2 = () => // 此時輸入框內顯示 123,能隨意增減值const case3 = () => // 此時輸入框內顯示 123,並且不能隨意增減值
case3
的情形即為簡化版的受控元件。
受控元件的實現
題目可以換個問法:當 input
的傳入屬性為 value
時(且沒有 onChange 屬性),如何禁用使用者的輸入事件的同時又能獲取焦點?
image
首先想到了 html 自帶屬性 readonly、disable,它們都能禁止使用者的輸入,但是它們不能滿足獲取焦點這個條件。結合前文 onChange
的實現是監聽 input
事件,程式碼分為以下兩種情況:
1.dom 節點包含 value
屬性、onChange
屬性
2.dom 節點包含 value
屬性,不包含 onChange
屬性
程式碼如下:
function vdomToDom(vdom) { ... if (vdom.attributes && vdom.attributes.hasOwnProperty('onChange') && vdom.attributes.hasOwnProperty('value')) { // 受控元件邏輯 ... dom.addEventListener('input', (e) => { changeCb.call(this, e) dom.value = oldValue }) ... } if (vdom.attributes && !vdom.attributes.hasOwnProperty('onChange') && vdom.attributes.hasOwnProperty('value')) { // 受控元件邏輯 ... dom.addEventListener('input', (e) => { dom.value = oldValue }) ... } ... }
可以發現它們的核心都在這段程式碼上:
dom.addEventListener('input', (e) => { changeCb.call(this, e) dom.value = oldValue })
區別是當有 onChange 屬性
時,能提供相應的回撥函式 changeCb
透過事件迴圈機制改變表單的值。看如下兩個例子的比較:
const App = () =>
效果如下:
image
class App extends Component { constructor() { super() this.state = { num: 123 } this.change = this.change.bind(this) } change(e) { this.setState({ num: e.target.value }) } render() { return () } }
這段程式碼中的 change
函式即上個段落所謂的 changeCb
函式,透過 setState
的事件迴圈機制改變表單的值。
效果如下:
image
至此,模擬了受控元件的實現。
作者:牧云云
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2249/viewspace-2814865/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 從 0 到 1 實現 React 系列 —— 5.PureComponent 實現 && HOC 探幽React
- 從0到1實現PromisePromise
- 從0到1實現VueUI庫思路VueUI
- 從0到1:React專案中的Webpack配置實戰ReactWeb
- 從0到1實現一個模組間通訊的服務元件元件
- 從0到1實現自己的阻塞佇列(上)佇列
- 從0到1實現專案Docker編排部署Docker
- vue 由0到1實現Vue
- react全家桶從0到1(react-router4、redux、redux-saga)ReactRedux
- 【React 實戰教程】從0到1 構建 github star管理工具ReactGithub
- 從0到1優雅的實現PHP多程式管理PHP
- 從0到1,企業如何實現精益生產?
- 從 0 到 1 實現一款簡易版 WebpackWeb
- 【深入理解Go】從0到1實現一個validatorGo
- 從0到1實現一個簡單計算器
- PHash從0到1
- node專案從0到1實戰
- Electron 應用如何利用 create-react-app 從 0 到 1ReactAPP
- 【深入理解Go】從0到1實現一個filter(middleware)GoFilter
- [譯] Flutter 從 0 到 1Flutter
- 從Android到React Native開發(二、通訊與模組實現)AndroidReact Native
- React 中的 onInput/onChangeReact
- React受控元件和非受控元件React元件
- 從0到1設計一個react-spa後臺應用React
- 從 0 到 1 認識 TypescriptTypeScript
- 工業「嫁衣」,從0到1
- 0到1,Celery從入門到出家
- 小冊《從 0 到 1 實現天氣小程式》跳坑記一
- React之受控元件和非受控元件React元件
- React 之受控元件和非受控元件React元件
- 做產品,選擇從0到1還是從1到N?
- 深入解析React受控元件與非受控元件React元件
- Android輪播圖從0到1Android
- webpack從0到1使用指南Web
- 學習seo如何從0到1
- DNSLOG平臺搭建從0到1DNS
- gtest學習教程(從0到1)
- Combine 框架,從0到1 —— 1.核心概念框架