最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談React深度編程之受控組件與非受控組件

 更新時間:2017年12月26日 08:40:23   作者:司徒正美  
這篇文章主要介紹了淺談React深度編程之受控組件與非受控組件,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

受控組件與非受控組件在官網(wǎng)與國內(nèi)網(wǎng)上的資料都不多,有些人覺得它可有可不有,也不在意。這恰恰顯示React的威力,滿足不同規(guī)模大小的工程需求。譬如你只是做ListView這樣簡單的數(shù)據(jù)顯示,將數(shù)據(jù)拍出來,那么for循壞與 {} 就足夠了,但后臺系統(tǒng)存在大量報表,不同的表單聯(lián)動,缺了受控組件真的不行。

受控組件與非受控組件是React處理表單的入口。從React的思路來講,作者肯定讓數(shù)據(jù)控制一切,或者簡單的理解為,頁面的生成與更新得忠實地執(zhí)行JSX的指令。

但是表單元素有其特殊之處,用戶可以通過鍵盤輸入與鼠標(biāo)選擇,改變界面的顯示。界面的改變也意味著有一些數(shù)據(jù)被改動,比較明顯的是input的 value ,textarea的 innerHTML ,radio/checkbox的 checked ,不太明顯的是option的 selected 與 selectedIndex ,這兩個是被動修改的。

 <input value="{this.state.value}"/>

 當(dāng)input.value是由組件的state.value拍出來的,當(dāng)用戶進(jìn)行輸入修改后,然后JSX再次重刷視圖,這時input.value是采取用戶的新值還是state的新值?基于這個分歧,React給出一個折衷的方案,兩者都支持,于是就產(chǎn)生了今天的主題了。

React認(rèn)為value/checked不能單獨存在,需要與onInput/onChange/disabed/readOnly等控制value/checked的屬性或事件一起使用。 它們共同構(gòu)成 受控組件 ,受控是受JSX的控制。如果用戶沒有寫這些額外的屬性與事件,那么框架內(nèi)部會給它添加一些事件,如onClick, onInput, onChange,阻止你進(jìn)行輸入或選擇,讓你無法修改它的值。在框架內(nèi)部,有一個頑固的變量,我稱之為 persistValue,它一直保持JSX上次賦給它的值,只能讓內(nèi)部事件修改它。

因此我們可以斷言,受控組件是可通過 事件 完成的對value的控制。

在受控組件中,persistValue總能被刷新。

我們再看非受控組件,既然value/checked已經(jīng)被占用了,React啟用了HTML中另一組被忽略的屬性defaultValue/defaultChecked。一般認(rèn)為它們是與value/checked相通的,即,value不存在的情況下,defaultValue的值就當(dāng)作是value。

上面我們已經(jīng)說過,表單元素的顯示情況是由內(nèi)部的 persistValue 控制的,因此defaultXXX也會同步persistValue,然后再由persistValue同步DOM。但非受控組件的出發(fā)點是忠實于用戶操作,如果用戶在代碼中

input.value = "xxxx"

以后

<input defaultvalue="{this.state.value}"/>

就再不生效,一直是xxxx。

它怎么做到這一點,怎么辨識這個修改是來自框架內(nèi)部或外部呢?我翻看了一下React的源碼,原來它有一個叫valueTracker的東西跟蹤用戶的輸入

var tracker = {
  getValue: function () {
   return currentValue;
  },
  setValue: function (value) {
   currentValue = '' + value;
  },
  stopTracking: function () {
   detachTracker(node);
   delete node[valueField];
  }
 };
 return tracker;
}

這個東西又是通過Object.defineProperty打進(jìn)元素的value/checked的內(nèi)部,因此就知曉用戶對它的取值賦值操作。

但value/checked還是兩個很核心的屬性,涉及到太多內(nèi)部機(jī)制(比如說value與oninput, onchange, 輸入法事件oncompositionstart,

compositionchange, oncompositionend, onpaste, oncut),為了平緩地修改value/checked,

還要用到 Object.getOwnPropertyDescriptor 。如果我要兼容IE8,沒有這么高級的玩藝兒。我采取另一種更安全的方式,

只用Object.defineProperty修改 defaultValue/defaultChecked 。

首先我為元素添加一個 _uncontrolled 的屬性,用來表示我已經(jīng)劫持過defaultXXX。 然后描述對象 ( Object.defineProperty的第三個參數(shù) )的set方法里面再添加一個開關(guān), _observing 。在框架內(nèi)部更新視圖,此值為false,更新完,它置為true。

這樣就知曉 input.defaultValue = “xxx”時,這是由用戶還是框架修改的。

if (!dom._uncontrolled) {
  dom._uncontrolled = true;
  inputMonitor.observe(dom, name); //重寫defaultXXX的setter/getter
}
dom._observing = false;//此時是框架在修改視圖,因此需要關(guān)閉開關(guān)
dom[name] = val;
dom._observing = true;//打開開關(guān),來監(jiān)聽用戶的修改行為

inputMonitor的實現(xiàn)如下

export var inputMonitor = {};
var rcheck = /checked|radio/;
var describe = {
  set: function(value) {
    var controllProp = rcheck.test(this.type) ? "checked" : "value";
    if (this.type === "textarea") {
      this.innerHTML = value;
    }
    if (!this._observing) {
      if (!this._setValue) {
        //defaultXXX只會同步一次_persistValue
        var parsedValue = (this[controllProp] = value);
        this._persistValue = Array.isArray(value) ? value : parsedValue;
        this._setValue = true;
      }
    } else {
      //如果用戶私下改變defaultValue,那么_setValue會被抺掉
      this._setValue = value == null ? false : true;
    }
    this._defaultValue = value;
  },
  get: function() {
    return this._defaultValue;
  },
  configurable: true
};
 
inputMonitor.observe = function(dom, name) {
  try {
    if ("_persistValue" in dom) {
      dom._setValue = true;
    }
    Object.defineProperty(dom, name, describe);
  } catch (e) {}
};

又不小心貼了這么燒腦的代碼,這是碼農(nóng)的壞毛病。不過,到這步,大家都明白,無論是官方react還是anu/qreact都是通過Object.defineProperty來控制用戶的輸入的。

于是我們可以理解以下的代碼的行為了

  var a = ReactDOM.render(<textarea defaultValue="foo" />, container);
  ReactDOM.render(<textarea defaultValue="bar" />, container);
  ReactDOM.render(<textarea defaultValue="noise" />, container);
  expect(a.defaultValue).toBe("noise");
  expect(a.value).toBe("foo");
  expect(a.textContent).toBe("noise");
  expect(a.innerHTML).toBe("noise");

由于用戶一直沒有手動修改 defaultValue, dom._setValue 一直為 false/undefined ,因此 _persistValue 一直能修改。

另一個例子:

var renderTextarea = function(component, container) {
  if (!container) {
    container = document.createElement("div");
  }
  const node = ReactDOM.render(component, container);
  node.defaultValue = node.innerHTML.replace(/^\n/, "");
  return node;
};
 
const container = document.createElement("div");
//注意這個方法,用戶在renderTextarea中手動改變了defaultValue,_setValue就變成true
const node = renderTextarea(<textarea defaultValue="giraffe" />, container);
 
expect(node.value).toBe("giraffe");
 
// _setValue后,gorilla就不能同步到_persistValue,因此還是giraffe
renderTextarea(<textarea defaultValue="gorilla" />, container);
// expect(node.value).toEqual("giraffe");
 
node.value = "cat";
// 這個又是什么回事了呢,因此非監(jiān)控屬性是在diffProps中批量處理的,在監(jiān)控屬性,則是在更后的方法中處理
// 檢測到node.value !== _persistValue,于是重寫 _persistValue = node.value,于是輸出cat
renderTextarea(<textarea defaultValue="monkey" />, container);
expect(node.value).toEqual("cat");

純文本類:text, textarea, JSX的值,總是往字符串轉(zhuǎn)換

type=”number”的控制,值總是為數(shù)字,不填或為“”則轉(zhuǎn)換為“0”

radio有聯(lián)動效果,同一父節(jié)點下的相同name的radio控制只能選擇一個。

select的value/defaultValue支持?jǐn)?shù)組,不做轉(zhuǎn)換,但用戶對底下的option元素做增刪操作,selected會跟著變動。

此外select還有模糊匹配與精確匹配之分。

//精確匹配
var dom = ReactDOM.render(
  <select value={222}>
    <option value={111}>aaa</option>
    <option value={"222"}>xxx</option>
    <option value={222}>bbb</option>
    <option value={333}>ccc</option>
  </select>,
  container
);
expect(dom.options[2].selected).toBe(true);//選中第三個
//模糊匹配
var dom = ReactDOM.render(
  <select value={222}>
    <option value={111}>aaa</option>
    <option value={"222"}>xxx</option>
    <option value={333}>ccc</option>
  </select>,
  container
);
expect(dom.options[2].selected).toBe(true);//選中第二個

凡此種種,React/anu都是做了大量工作,迷你如preact/react-lite之流則可能遇坑。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 詳解React中的setState執(zhí)行機(jī)制

    詳解React中的setState執(zhí)行機(jī)制

    setState是React組件中用于更新狀態(tài)的方法,是類組件中的方法,用于更新組件的狀態(tài)并重新渲染組件,本文給大家詳細(xì)介紹了React中的setState執(zhí)行機(jī)制,文中通過代碼示例介紹的非常詳細(xì),需要的朋友可以參考下
    2023-12-12
  • React?Fiber原理深入分析

    React?Fiber原理深入分析

    Fiber可以理解為一個執(zhí)行單元,每次執(zhí)行完一個執(zhí)行單元,React?Fiber就會檢查還剩多少時間,如果沒有時間則將控制權(quán)讓出去,然后由瀏覽器執(zhí)行渲染操作,這篇文章主要介紹了React?Fiber架構(gòu)原理剖析,需要的朋友可以參考下<BR>
    2023-01-01
  • react中useEffect函數(shù)的詳細(xì)用法(最新推薦)

    react中useEffect函數(shù)的詳細(xì)用法(最新推薦)

    useEffect是React中的一個Hook,用于在函數(shù)組件中處理副作用(如數(shù)據(jù)獲取、訂閱、手動更改 DOM 等),useEffect屬于組件的生命周期方法,下面通過本文給大家分享react中useEffect函數(shù)的詳細(xì)用法,感興趣的朋友跟隨小編一起看看吧
    2024-06-06
  • 淺談React 中的淺比較是如何工作的

    淺談React 中的淺比較是如何工作的

    React 中淺比較的概念無處不在,它在不同的流程中起著關(guān)鍵的作用,本文主要介紹了React 中的淺比較是如何工作的,具有一定的參考價值,感興趣的可以了解一下
    2022-04-04
  • useEffect支持async及await使用方式

    useEffect支持async及await使用方式

    這篇文章主要為大家介紹了useEffect支持async及await的使用方式示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • React 組件通信的多種方式與最佳實踐

    React 組件通信的多種方式與最佳實踐

    在現(xiàn)代前端開發(fā)中,組件化是 React 的核心理念之一,組件之間的通信是構(gòu)建復(fù)雜應(yīng)用的重要組成部分,在這篇文章中,我們將深入探討 React 組件通信的多種方式,包括它們的優(yōu)缺點、使用場景以及最佳實踐,需要的朋友可以參考下
    2024-11-11
  • React文件分段上傳實現(xiàn)方法詳解

    React文件分段上傳實現(xiàn)方法詳解

    這篇文章主要介紹了React文件分段上傳實現(xiàn)方法,將文件切成多個小的文件;將切片并行上傳;所有切片上傳完成后,服務(wù)器端進(jìn)行切片合成;當(dāng)分片上傳失敗,可以在重新上傳時進(jìn)行判斷,只上傳上次失敗的部分實現(xiàn)斷點續(xù)傳;當(dāng)切片合成為完整的文件,通知客戶端上傳成功
    2022-11-11
  • Can't?perform?a?React?state?update?on?an?unmounted?component報錯解決

    Can't?perform?a?React?state?update?on?an?unmoun

    這篇文章主要為大家介紹了Can't?perform?a?React?state?update?on?an?unmounted?component報錯解決方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • React獲取url后面參數(shù)的值示例代碼

    React獲取url后面參數(shù)的值示例代碼

    這篇文章主要介紹了React獲取url后面參數(shù)的值示例代碼,代碼簡單易懂,文末給大家補(bǔ)充介紹了react獲取URL中參數(shù)方法,需要的朋友可以參考下
    2022-12-12
  • React學(xué)習(xí)筆記之事件處理(二)

    React學(xué)習(xí)筆記之事件處理(二)

    這篇文章主要跟大家介紹了關(guān)于React中事件處理的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)React具有一定的參考學(xué)習(xí)價值,需要的朋友們下面跟著小編一起來學(xué)習(xí)學(xué)習(xí)吧。
    2017-07-07

最新評論

苍南县| 武陟县| 盐城市| 冀州市| 高尔夫| 黎平县| 梁山县| 台北县| 平塘县| 宜兰县| 广丰县| 青铜峡市| 临高县| 长兴县| 星子县| 汶川县| 红桥区| 中牟县| 永寿县| 大庆市| 余干县| 建德市| 花莲县| 平潭县| 江永县| 蓝田县| 新竹市| 会宁县| 东乌珠穆沁旗| 昔阳县| 丰镇市| 义乌市| 库尔勒市| 嘉荫县| 岳池县| 资中县| 江达县| 威远县| 双鸭山市| 斗六市| 宝应县|