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

react中實(shí)現(xiàn)修改input的defaultValue

 更新時(shí)間:2023年05月11日 14:29:09   作者:東都花神  
這篇文章主要介紹了react中實(shí)現(xiàn)修改input的defaultValue方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

react中修改input的defaultValue

在使用 react 進(jìn)行開發(fā)時(shí),我們一般使用類組件的 setState 或者 hooks 實(shí)現(xiàn)頁面數(shù)據(jù)的實(shí)時(shí)更新,但在某些表單組件中,這一操作會(huì)失效,元素的數(shù)據(jù)卻無法更新,令人苦惱

比如下面這個(gè)例子

import React, { useState } from "react";
function Demo() {
    const [num, setNum] = useState(0);
    return (
        <>
            <input defaultValue={num} />
            <button onClick={() => setNum(666)}>button</button>
        </>
    );
}
export default Demo;

理論上按鈕點(diǎn)擊后會(huì)執(zhí)行 setNum 函數(shù),并觸發(fā) Demo 組件重新渲染,input 展示最新值,但實(shí)際上 Input 值并沒有更新到最新

如下截圖:

從截圖可以看出,num 值確實(shí)已經(jīng)更新到了最新,但是 Input 中的值卻始終沒有同步更新,如何解決這個(gè)問題呢,很簡(jiǎn)單,在 input 上添加一個(gè) key 即可。

但是僅僅知道解決方案還不夠,奔著打破砂鍋問到底的態(tài)度,我們今天就來探究下為啥通過修改 key 可以強(qiáng)制更新?

在開始之前,首先要明確一點(diǎn): input 元素本身是沒有 defaultValue 這個(gè)屬性,如下圖(點(diǎn)我查看),這個(gè)屬性是 react 框架自己添加,一直以為是原生屬性的我留下了沒有技術(shù)的眼淚。

換句話說,如果不使用 react 框架,在 input 中是無法使用 defaultValue 屬性的。

下面是一個(gè)使用 defaultValue 的簡(jiǎn)單例子

<head>
  <script type="text/javascript">
    function GetDefValue() {
      var elem = document.getElementById("myInput");
      var defValue = elem.defaultValue;
      var currvalue = elem.value;
      if (defValue == currvalue) {
        alert("The contents of the input field have not changed!");
      } else {
        alert("The default contents were " + defValue +
          "\n  and the new contents are " + currvalue);
      }
    }
  </script>
</head>
<body>
  <button onclick="GetDefValue ();">Get defaultValue!</button>
  <input type="text" id="myInput" value="Initial value">
  The initial value will not be affected if you change the text in the input field.
</body>

雖然 input 標(biāo)簽上不能直接設(shè)置 defaultValue,但是卻可以通過操作 HTMLInputElement 對(duì)象設(shè)置和獲取 defaultValue,需要注意的是,這里通過設(shè)置 defaultValue 也會(huì)同步修改 value 的值,但是因?yàn)?react 內(nèi)部自定實(shí)現(xiàn)了 input 組件,所以在 react 中通過修改 defaultValue 并不會(huì)影響到 value 值,具體參看 ReactDOMInput.js。

以上是一些前置知識(shí),接下來是具體的分析。

通過上面的介紹,我們首先要看下 react 是如何處理 defaultValue 這個(gè)屬性的,這個(gè)屬性是在 postMountWrapper 中設(shè)置的,源碼如下:

export function postMountWrapper(
  element: Element,
  props: Object,
  isHydrating: boolean,
) {
  const node = ((element: any): InputWithWrapperState);
  if (props.hasOwnProperty('value') || props.hasOwnProperty('defaultValue')) {
    const type = props.type;
    const isButton = type === 'submit' || type === 'reset';
    if (isButton && (props.value === undefined || props.value === null)) {
      return;
    }
    const initialValue = toString(node._wrapperState.initialValue);
    if (!isHydrating) {
      if (initialValue !== node.value) {
        node.value = initialValue;
      }
    }
    node.defaultValue = initialValue;
  }
}

通過源碼可以看出,react 內(nèi)部會(huì)獲取傳入的 defaultValue,然后同時(shí)掛載到 node 的 value 和 defaultValue上,這樣初次渲染的時(shí)候頁面就會(huì)展示傳入的默認(rèn)屬性,注意這個(gè)函數(shù)只會(huì)在初始化的時(shí)候執(zhí)行。

接下來我們看下點(diǎn)擊按鈕后的邏輯,重點(diǎn)關(guān)注 mapRemainingChildren 函數(shù):

function mapRemainingChildren(
  returnFiber: Fiber,
  currentFirstChild: Fiber,
): Map<string | number, Fiber> {
  // Add the remaining children to a temporary map so that we can find them by
  // keys quickly. Implicit (null) keys get added to this set with their index
  // instead.
  const existingChildren: Map<string | number, Fiber> = new Map();
  let existingChild = currentFirstChild;
  while (existingChild !== null) {
    if (existingChild.key !== null) {
      existingChildren.set(existingChild.key, existingChild);
    } else {
      existingChildren.set(existingChild.index, existingChild);
    }
    existingChild = existingChild.sibling;
  }
  return existingChildren;
}

這個(gè)函數(shù)會(huì)給每一個(gè)子元素添加一個(gè) key 值,并添加到一個(gè) set 中,之后會(huì)執(zhí)行 updateFromMap 方法

function updateFromMap(
  existingChildren: Map<string | number, Fiber>,
  returnFiber: Fiber,
  newIdx: number,
  newChild: any,
  lanes: Lanes,
): Fiber | null {
  // ...
  if (typeof newChild === 'object' && newChild !== null) {
    switch (newChild.$$typeof) {
      case REACT_ELEMENT_TYPE: {
        const matchedFiber =
          existingChildren.get(
            newChild.key === null ? newIdx : newChild.key,
          ) || null;
        return updateElement(returnFiber, matchedFiber, newChild, lanes);
      }
    }
  }
  // ...
  return null;
}

在這個(gè)方法會(huì)通過最新傳入的 key 獲取 上面 set 中的值,然后將值傳入到 updateElement 中

function updateElement(
  returnFiber: Fiber,
  current: Fiber | null,
  element: ReactElement,
  lanes: Lanes,
): Fiber {
  const elementType = element.type;
  if (current !== null) {
    if (
      current.elementType === elementType ||
      (enableLazyElements &&
        typeof elementType === 'object' &&
        elementType !== null &&
        elementType.$$typeof === REACT_LAZY_TYPE &&
        resolveLazy(elementType) === current.type)
    ) {
      // Move based on index
      const existing = useFiber(current, element.props);
      existing.ref = coerceRef(returnFiber, current, element);
      existing.return = returnFiber;
      if (__DEV__) {
        existing._debugSource = element._source;
        existing._debugOwner = element._owner;
      }
      return existing;
    }
  }
  // Insert
  const created = createFiberFromElement(element, returnFiber.mode, lanes);
  created.ref = coerceRef(returnFiber, current, element);
  created.return = returnFiber;
  return created;
}

因?yàn)槲覀冊(cè)诟碌臅r(shí)候修改了 key 值,所以這里的 current 是不存在的,走的是重新創(chuàng)建的代碼,如果我們沒有傳入 key 或者 key 沒有改變,那么走的的就是復(fù)用的代碼,所以,如果使用 map 循環(huán)了多個(gè) input 然后使用下標(biāo)作為 key,就會(huì)出現(xiàn)修改后多個(gè) input 狀態(tài)不一致的詳情,因此,表單組件不推薦使用下標(biāo)作為 key,容易出 bug。

之后是更新代碼的邏輯,input 屬性的更新操作是在 updateWrapper 中進(jìn)行的,我們看下這個(gè)函數(shù)的源碼:

export function updateWrapper(element: Element, props: Object) {
  const node = ((element: any): InputWithWrapperState);
  updateChecked(element, props);
  // 重點(diǎn),這里只會(huì)獲取 value 的值,不會(huì)再獲取 defaultValue 的值
  const value = getToStringValue(props.value);
  const type = props.type;
  if (value != null) {
    if (type === 'number') {
      if (
        (value === 0 && node.value === '') ||
        // We explicitly want to coerce to number here if possible.
        // eslint-disable-next-line
        node.value != (value: any)
      ) {
        node.value = toString((value: any));
      }
    } else if (node.value !== toString((value: any))) {
      node.value = toString((value: any));
    }
  } else if (type === 'submit' || type === 'reset') {
    // Submit/reset inputs need the attribute removed completely to avoid
    // blank-text buttons.
    node.removeAttribute('value');
    return;
  }
  // 根據(jù)設(shè)置的 value 或者 defaultValue 來 input 元素的屬性
  if (props.hasOwnProperty('value')) {
    setDefaultValue(node, props.type, value);
  } else if (props.hasOwnProperty('defaultValue')) {
    setDefaultValue(node, props.type, getToStringValue(props.defaultValue));
  }
}

這里的 element 其實(shí)就是 input 對(duì)象,但是由于在設(shè)置時(shí)僅獲取 props 中的 value,而沒有獲取 defaultValue,第 21 行不會(huì)執(zhí)行,所以頁面中的值也不會(huì)更新,但是第34行依然還是會(huì)執(zhí)行,而且頁面還出現(xiàn)了十分詭異的現(xiàn)象

如下圖:

頁面展示狀態(tài)和源碼狀態(tài)不一致,HTML中的屬性已經(jīng)修改為了 666,但是頁面依然展示的 0,估計(jì)是 react 在實(shí)現(xiàn) input 時(shí)留下的一個(gè)隱藏 bug。

總結(jié)一下

react 內(nèi)部會(huì)給 Demo 組件中的每一個(gè)子元素添加一個(gè) key(傳入或下標(biāo)),然后將 key 作為 set 的鍵,之后通過最新的 key 去獲取 set 中儲(chǔ)存的值,如果存在復(fù)用原來元素,更新屬性,如果不存在,重新創(chuàng)建,修改 key 可以達(dá)到每次都重新創(chuàng)建元素,而不是復(fù)用原來的元素,這就是修改 key 進(jìn)而達(dá)到修改 defaultValue 的原因。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • react獲取input輸入框的值的方法示例

    react獲取input輸入框的值的方法示例

    這篇文章主要介紹了react獲取input輸入框的值的方法示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • React中styled-components的使用

    React中styled-components的使用

    styled-components 樣式化組件,主要作用是它可以編寫實(shí)際的CSS代碼來設(shè)計(jì)組件樣式,本文主要介紹了React中styled-components的使用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2022-04-04
  • React?跨端動(dòng)態(tài)化核心技術(shù)實(shí)例分析

    React?跨端動(dòng)態(tài)化核心技術(shù)實(shí)例分析

    這篇文章主要為大家介紹了React?跨端動(dòng)態(tài)化核心技術(shù)實(shí)例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • React利用路由實(shí)現(xiàn)登錄界面的跳轉(zhuǎn)

    React利用路由實(shí)現(xiàn)登錄界面的跳轉(zhuǎn)

    這篇文章主要介紹了React利用路由實(shí)現(xiàn)登錄界面的跳轉(zhuǎn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • React Native自定義路由管理的深入理解

    React Native自定義路由管理的深入理解

    路由管理的功能主要指的頁面跳轉(zhuǎn)、goBack、帶參數(shù)跳轉(zhuǎn)等功能,這篇文章主要給大家介紹了關(guān)于React Native自定義路由管理的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • React簡(jiǎn)單介紹

    React簡(jiǎn)單介紹

    React 是一個(gè)用于構(gòu)建用戶界面的 JavaScript 庫,主要用于構(gòu)建 UI,而不是一個(gè) MVC 框架,React 擁有較高的性能,代碼邏輯非常簡(jiǎn)單,越來越多的人已開始關(guān)注和使用它
    2017-05-05
  • React Hook 監(jiān)聽localStorage更新問題

    React Hook 監(jiān)聽localStorage更新問題

    這篇文章主要介紹了React Hook 監(jiān)聽localStorage更新問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • Shopee在React?Native?架構(gòu)方面的探索及發(fā)展歷程

    Shopee在React?Native?架構(gòu)方面的探索及發(fā)展歷程

    這篇文章主要介紹了Shopee在React?Native?架構(gòu)方面的探索,本文會(huì)從發(fā)展歷史、架構(gòu)模型、系統(tǒng)設(shè)計(jì)、遷移方案四個(gè)方向逐一介紹我們?nèi)绾我徊讲降貪M足多團(tuán)隊(duì)在復(fù)雜業(yè)務(wù)中的開發(fā)需求,需要的朋友可以參考下
    2022-07-07
  • 2個(gè)奇怪的react寫法

    2個(gè)奇怪的react寫法

    大家好,我卡頌。雖然React官網(wǎng)用大量篇幅介紹最佳實(shí)踐,但因JSX語法的靈活性,所以總是會(huì)出現(xiàn)奇奇怪怪的React寫法。本文介紹2種奇怪(但在某些場(chǎng)景下有意義)的React寫法。也歡迎大家在評(píng)論區(qū)討論你遇到過的奇怪寫法
    2023-03-03
  • React處理復(fù)雜圖片樣式的方法詳解

    React處理復(fù)雜圖片樣式的方法詳解

    這篇文章主要為大家詳細(xì)介紹了React處理復(fù)雜圖片樣式的方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-04-04

最新評(píng)論

大连市| 阜宁县| 杂多县| 丹阳市| 林口县| 邛崃市| 昔阳县| 清镇市| 微山县| 龙江县| 阳东县| 郧西县| 溆浦县| 赤峰市| 广丰县| 古浪县| 锦州市| 习水县| 亚东县| 宁乡县| 台安县| 息烽县| 镇平县| 周至县| 平定县| 融水| 竹北市| 宣恩县| 绥德县| 新闻| 新田县| 通化县| 钟山县| 五家渠市| 宁波市| 宿州市| 灵山县| 洪泽县| 房山区| 荥经县| 措美县|