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

React八大常見錯(cuò)誤及其解決方案

 更新時(shí)間:2024年03月11日 08:33:22   作者:前端貓貓教  
這篇文章主要介紹了React八大常見錯(cuò)誤及其解決方案,并通過(guò)代碼示例介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)react有一定的幫助,感興趣的朋友可以參考下

我們會(huì)深度學(xué)習(xí)這 8 大錯(cuò)誤消息,包括但不限于:

  • 警告:列表中的每個(gè)子元素都應(yīng)該有一個(gè)唯一的 key 屬性
  • 防止在 key 中使用數(shù)組索引
  • React Hook useXXX 的條件調(diào)用。React Hooks 必須在每個(gè)組件渲染中以完全相同的順序調(diào)用
  • React Hook 缺少依賴:“XXX”。包含它或刪除依賴數(shù)組
  • 無(wú)法對(duì)已卸載的組件執(zhí)行 React 狀態(tài)更新
  • 重新渲染次數(shù)過(guò)多。React 限制渲染次數(shù),防止無(wú)限循環(huán)
  • 對(duì)象作為 React 子元素?zé)o效/函數(shù)作為 React 子元素?zé)o效
  • 相鄰的 JSX 元素必須包含在封閉標(biāo)簽中

警告:列表中的每個(gè)子元素都應(yīng)該有一個(gè)唯一的 key 屬性

假設(shè)我們有一個(gè)卡片列表,如下所示:

import { Card } from './Card'

const data = [
  { id: 1, text: '關(guān)注' },
  { id: 2, text: '點(diǎn)贊' },
  { id: 3, text: '收藏' }
]

export default function App() {
  return (
    <div className="container">
      {data.map(content => (
        <div className="card">
          <Card text={content.text} />
        </div>
      ))}
    </div>
  )
}

React 開發(fā)中最常見的事情之一就是,獲取數(shù)組元素,并使用組件根據(jù)元素內(nèi)容渲染它們。得益于 JSX,我們可以使用 Array.map() 函數(shù)輕松將循環(huán)邏輯嵌入到組件中,并從回調(diào)中返回所需的組件。

雖然但是,在瀏覽器控制臺(tái)中收到 React 警告也司空見慣,提示列表中的每個(gè)子元素都應(yīng)該有一個(gè)唯一的 key 屬性。在養(yǎng)成給每個(gè)子元素一個(gè)獨(dú)特的 key 屬性的習(xí)慣之前,我們可能會(huì)多次遭遇此警告,尤其是如果我們對(duì) React 經(jīng)驗(yàn)較少。但在養(yǎng)成習(xí)慣之前該如何解決呢?

正如警告所示,我們必須將 key 屬性添加到從 map 回調(diào)返回的 JSX 的最外層元素中。雖然但是,我們要使用的 key 有若干要求。key 應(yīng)該是:

  • 字符串或數(shù)字
  • 對(duì)于列表中的特定元素而言是唯一的
  • 跨渲染列表中該元素的代表
export default function App() {
  return (
    <div className="container">
      {data.map(content => (
        <div key={content.id} className="card">
          <Card text={content.text} />
        </div>
      ))}
    </div>
  )
}

雖然如果不遵守這些要求,我們的 App 也不會(huì)崩潰,但它可能會(huì)導(dǎo)致某些意外且通常不需要的行為。React 使用這些 key 來(lái)確定列表中的哪些子元素已更改,并使用該信息來(lái)確定可以重用先前 DOM 的哪些部分,以及重新渲染組件時(shí)應(yīng)該重新計(jì)算哪些部分。因此,我們始終建議添加這些 key

防止在 key 中使用數(shù)組索引

在上文警告的基礎(chǔ)上,我們將深入學(xué)習(xí)有關(guān) key 的同樣常見的 ESLint 警告。當(dāng)我們養(yǎng)成了在列表中生成的 JSX 中包含 key 屬性的習(xí)慣后,通常會(huì)出現(xiàn)下列警告。

import { Card } from './Card'

// 粉絲請(qǐng)注意,data 中沒有預(yù)生成的唯一 id
const data = [{ text: '關(guān)注' }, { text: '點(diǎn)贊' }, { text: '收藏' }]

export default function App() {
  return (
    <div className="container">
      {data.map((content, index) => (
        <div key={index} className="card">
          <Card text={content.text} />
        </div>
      ))}
    </div>
  )
}

有時(shí),我們的數(shù)據(jù)不會(huì)附加唯一標(biāo)識(shí)符。一個(gè)簡(jiǎn)單的解決方案就是,使用列表中當(dāng)前元素的索引。雖然但是,使用數(shù)組中元素的索引作為 key 的問題在于,它不能代表跨渲染的特定元素。

假設(shè)我們有一個(gè)包含多個(gè)元素的列表,并且用戶通過(guò)刪除第二個(gè)元素與它們進(jìn)行交互。對(duì)于第一個(gè)元素,其底層 DOM 結(jié)構(gòu)沒有任何改變;這反映在它的 key 上,它保持不變,第一個(gè)元素的 key 還是索引 0。

對(duì)于第三個(gè)元素及之后的項(xiàng)目,它們的內(nèi)容沒有改變,因此它們的底層結(jié)構(gòu)也不應(yīng)該改變。雖然但是,因?yàn)榈诙€(gè)元素被刪除了,所有其他元素的 key 屬性都會(huì)發(fā)生變化,因?yàn)檫@里的 key 是基于數(shù)組索引生成的。React 會(huì)假設(shè)它們已經(jīng)改變并重新計(jì)算它們的結(jié)構(gòu) —— 但這是不必要的。這會(huì)對(duì)性能產(chǎn)生負(fù)面影響,并且還可能導(dǎo)致不一致和不正確的狀態(tài)。

為了搞定這個(gè)問題,最重要的是要記住,key 不一定是 id。只要它們是唯一的,并且能代表生成的 DOM 結(jié)構(gòu),我們想使用的任何 key 都問題不大。

export default function App() {
  return (
    <div className="container">
      {data.map(content => (
        <div key={content.text} className="card">
          {/* 直接使用內(nèi)容作為 key 也能奏效 */}
          <Card text={content.text} />
        </div>
      ))}
    </div>
  )
}

React Hook useXXX 有條件地調(diào)用。React Hooks 必須在每個(gè)組件渲染中以完全相同的順序調(diào)用

我們可以在開發(fā)過(guò)程中以不同的方式優(yōu)化我們的代碼。我們力所能及的一件事就是,確保某些代碼只在需要該代碼的代碼分支中按需執(zhí)行。尤其是在處理時(shí)間或資源密集型的代碼時(shí),這可能會(huì)在性能方面產(chǎn)生巨大的差異。

const Toggle = () => {
  const [isOpen, setIsOpen] = useState(false)

  if (isOpen) {
    return <div>{/* ... */}</div>
  }
  const openToggle = useCallback(() => setIsOpen(true), [])
  return <button onClick={openToggle}>{/* ... */}</button>
}

不幸的是,將這種優(yōu)化技術(shù)應(yīng)用于 Hooks,會(huì)向我們提示不要條件調(diào)用 React Hooks 的警告,因?yàn)槲覀儽仨氃诿總€(gè)組件渲染中以相同的順序調(diào)用它們。

這是必要的,因?yàn)樵趦?nèi)部,React 使用 Hook 的調(diào)用順序來(lái)跟蹤其底層狀態(tài),并在渲染之間保留它們。如果我們打亂了這個(gè)順序,React 內(nèi)部將不再知道哪個(gè)狀態(tài)與 Hook 匹配。這會(huì)給 React 帶來(lái)重大問題,甚至可能導(dǎo)致錯(cuò)誤。

React Hooks 必須始終在組件的頂層無(wú)條件地調(diào)用。在實(shí)踐中,這通??梢詺w結(jié)為保留組件的第一部分用于 React Hook 初始化。

const Toggle = () => {
  const [isOpen, setIsOpen] = useState(false)
  const openToggle = useCallback(() => setIsOpen(true), [])

  if (isOpen) {
    return <div>{/* ... */}</div>
  }
  return <button onClick={openToggle}>{/* ... */}</button>
}

React Hook 缺少依賴:“XXX”。包含它或刪除依賴數(shù)組

React Hooks 一個(gè)有趣的地方在于依賴數(shù)組。幾乎每個(gè) React Hook 都接受數(shù)組形式的第二個(gè)參數(shù),我們可以在其中定義 Hook 的依賴。當(dāng)任何依賴發(fā)生變化時(shí),React 會(huì)檢測(cè)到它,并重新觸發(fā) Hook。

在官方文檔中,如果變量在 Hook 中使用,React 建議開發(fā)者始終將所有變量包含在依賴數(shù)組中,并在更改時(shí)影響組件的渲染。

為了搞定這個(gè)問題,建議在 react-hooks ESLint plugin 中使用 exhaustive-deps rule。當(dāng)任何 React Hook 未定義所有依賴時(shí),激活它會(huì)向我們自動(dòng)發(fā)出警告。

const Component = ({ value, onChange }) => {
  useEffect(() => {
    if (value) {
      onChange(value)
    }
  }, [value])
  // onChange 沒有作為依賴包含進(jìn)來(lái)
}

我們應(yīng)該深刻認(rèn)識(shí)到,依賴數(shù)組問題的原因與 JS 中閉包和作用域的概念有關(guān)。如果 React Hook 的主回調(diào)使用了其自身作用域之外的變量,那么它只能記住這些變量在執(zhí)行時(shí)的版本。

但是,當(dāng)這些變量發(fā)生更改時(shí),回調(diào)的閉包無(wú)法自動(dòng)獲取這些更改的版本。這可能會(huì)導(dǎo)致使用過(guò)時(shí)的依賴引用來(lái)執(zhí)行 React Hook 代碼,并導(dǎo)致與預(yù)期不同的行為。

因此,始終建議對(duì)依賴項(xiàng)數(shù)組進(jìn)行抽絲剝繭。這樣做可以搞定以這種方式調(diào)用 React Hooks 時(shí)可能出現(xiàn)的所有問題,因?yàn)樗鼘?React 指向要跟蹤的變量。當(dāng) React 檢測(cè)到任何變量的更改時(shí),它將重新運(yùn)行回調(diào),從而允許它獲取依賴的更改版本,并按預(yù)期運(yùn)行。

無(wú)法對(duì)已卸載的組件執(zhí)行 React 狀態(tài)更新

在處理組件中的異步數(shù)據(jù)或邏輯流時(shí),我們可能會(huì)在瀏覽器控制臺(tái)中遭遇運(yùn)行時(shí)錯(cuò)誤,告訴我們無(wú)法對(duì)已卸載的組件執(zhí)行狀態(tài)更新。問題在于,在組件樹中的某個(gè)位置,已卸載的組件會(huì)觸發(fā)狀態(tài)更新。

const Component = () => {
  const [data, setData] = useState(null)

  useEffect(() => {
    fetchAsyncData().then(data => setData(data))
  }, [])
}

這是由依賴于異步請(qǐng)求的狀態(tài)更新引起的。異步請(qǐng)求在組件生命周期的某個(gè)位置開始,比如在 useEffect Hook 內(nèi),但需要一段時(shí)間才能完成。

有多種方案可以搞定此問題,所有這些方案都可以歸類為兩個(gè)不同的概念。首先,可以跟蹤組件是否已安裝,我們可以據(jù)此執(zhí)行操作。

雖然這能奏效,但不建議這樣做。此方案的問題在于,它不必要地保留未安裝組件的引用,這會(huì)導(dǎo)致內(nèi)存泄漏和性能問題。

const Component = () => {
  const [data, setData] = useState(null)
  const isMounted = useRef(true)

  useEffect(() => {
    fetchAsyncData().then(data => {
      if (isMounted.current) {
        setData(data)
      }
    })

    return () => {
      isMounted.current = false
    }
  }, [])
}

第二種方案是首選方案,是在組件卸載時(shí)取消異步請(qǐng)求。某些異步請(qǐng)求庫(kù)已經(jīng)有一個(gè)機(jī)制來(lái)取消此類請(qǐng)求。如果是這樣,就像在 useEffect Hook 的清理回調(diào)期間取消請(qǐng)求一樣簡(jiǎn)單。

如果我們沒有使用這樣的庫(kù),我們可以使用 AbortController 實(shí)現(xiàn)同款需求。這些取消方法的唯一缺陷在于,它們完全依賴于庫(kù)的實(shí)現(xiàn)或?yàn)g覽器支持。

const Component = () => {
  const [data, setData] = useState(null)

  useEffect(() => {
    const controller = new AbortController()
    fetch(url, { signal: controller.signal }).then(data => setData(data))
    return () => {
      controller.abort()
    }
  }, [])
}

重新渲染次數(shù)過(guò)多。React 限制渲染次數(shù),防止無(wú)限循環(huán)

無(wú)限循環(huán)是每個(gè)開發(fā)者的大坑,React 開發(fā)者也不例外。幸運(yùn)的是,React 可以很好地檢測(cè)它們,并在整個(gè)設(shè)備變得無(wú)響應(yīng)之前向我們發(fā)出警告。

正如警告所示,問題在于我們的組件觸發(fā)了太多的重新渲染。當(dāng)組件在很短的時(shí)間內(nèi)排隊(duì)太多狀態(tài)更新時(shí),就會(huì)發(fā)生這種情況。導(dǎo)致無(wú)限循環(huán)的最常見原因在于:

  • 直接在渲染中執(zhí)行狀態(tài)更新
  • 未向事件處理程序提供正確的回調(diào)

如果我們?cè)庥鐾罹?,?qǐng)務(wù)必檢查組件的這兩個(gè)方面。

const Component = () => {
  const [count, setCount] = useState(0)

  setCount(count + 1) // 在渲染中更新狀態(tài)

  return (
    <div className="App">
      {/* onClick 沒有接受一個(gè)妥當(dāng)?shù)幕卣{(diào) */}
      <button onClick={setCount(prevCount => prevCount + 1)}>
        Increment that counter
      </button>
    </div>
  )
}

對(duì)象作為 React 子元素?zé)o效/函數(shù)作為 React 子元素?zé)o效

在 React 中,我們可以在組件中渲染很多東西到 DOM。選擇幾乎是無(wú)窮無(wú)盡的:所有 HTML 標(biāo)簽、任何 JSX 元素、任意原始 JS 值、先前值的數(shù)組,甚至 JS 表達(dá)式,只要它們被評(píng)估為任何先前值。

盡管如此,不幸的是,React 仍然不接受所有可能作為 React 子元素存在的東西。具體而言,我們無(wú)法將對(duì)象和函數(shù)渲染到 DOM,因?yàn)檫@兩個(gè)數(shù)據(jù)值不會(huì)評(píng)估為 React 可以渲染到 DOM 中的任何有意義的內(nèi)容。因此,任何這樣做的嘗試都會(huì)導(dǎo)致 React 以上述錯(cuò)誤的形式發(fā)出警告。

如果我們?cè)庥鲞@些錯(cuò)誤之一,建議驗(yàn)證我們正在渲染的變量是否是預(yù)期的類型。大多數(shù)情況下,這個(gè)問題是由于在 JSX 中渲染子元素或變量而引起的,假設(shè)它是一個(gè)原始值,但實(shí)際上,它是一個(gè)對(duì)象或函數(shù)。作為一種預(yù)防方法,擁有適當(dāng)?shù)念愋拖到y(tǒng)可以提供很大幫助。

const Component = ({ body }) => (
  <div>
    <h1>{/* */}</h1>
    {/* 必須確保 body prop 是有效的 React 子元素 */}
    <div className="body">{body}</div>
  </div>
)

相鄰的 JSX 元素必須包含在封閉標(biāo)簽中

React 最大的優(yōu)勢(shì)之一在于,能夠通過(guò)組合許多較小的組件來(lái)構(gòu)建整個(gè) App。每個(gè)組件都可以以 JSX 的形式定義它應(yīng)該渲染的 UI 部分,這最終有助于 App 的整個(gè) DOM 結(jié)構(gòu)。

const Component = () => (
  <div><NiceComponent /></div>
  <div><GoodComponent /></div>
);

由于 React 的復(fù)合性質(zhì),一個(gè)常見的嘗試是在一個(gè)組件的根中返回兩個(gè)僅在另一個(gè)組件中使用的 JSX 元素。雖然但是,這樣做會(huì)令人驚訝地向 React 開發(fā)者發(fā)出警告,告訴我們必須將相鄰的 JSX 元素包裝在封閉標(biāo)簽中。

從普通 React 開發(fā)者的角度來(lái)看,該組件只會(huì)在另一個(gè)組件內(nèi)部使用。因此,在我們的心智模型中,從組件返回兩個(gè)元素是完全有意義的,因?yàn)闊o(wú)論外部元素是在該組件還是父組件中定義,生成的 DOM 結(jié)構(gòu)都是相同的。

雖然但是,React 無(wú)法做出這個(gè)假設(shè)。該組件有可能在根中使用并破壞 App,因?yàn)樗鼘?dǎo)致無(wú)效的 DOM 結(jié)構(gòu)。

React 開發(fā)者應(yīng)該始終將從組件返回的多個(gè) JSX 元素包裝在封閉標(biāo)記中。這可以是一個(gè)元素、一個(gè)組件或 React 的 Fragment,如果你確定該組件不需要外部元素。

const Component = () => (
  <React.Fragment>
    <div>
      <NiceComponent />
    </div>
    <div>
      <GoodComponent />
    </div>
  </React.Fragment>
)

總結(jié)

在開發(fā)過(guò)程中邂逅 bug 是不可避免的一部分。雖然但是,我們處理這些錯(cuò)誤消息的方案也表明了作為 React 開發(fā)者的技術(shù)修養(yǎng)。為了正確地做到這一點(diǎn),有必要了解這些錯(cuò)誤并知道它們發(fā)生的原因。

本文科普了我們?cè)?React 開發(fā)過(guò)程中會(huì)遭遇的八大最常見的 React 錯(cuò)誤消息。我們介紹了錯(cuò)誤消息背后的含義、潛在錯(cuò)誤、如何解決錯(cuò)誤,以及如果不修復(fù)錯(cuò)誤會(huì)發(fā)生什么。

有了這些知識(shí)儲(chǔ)備,我們現(xiàn)在可以更徹底地理解這些錯(cuò)誤,并感到有能力編寫更少的包含這些錯(cuò)誤的代碼,從而產(chǎn)生更高質(zhì)量的代碼。

以上就是React八大常見錯(cuò)誤及其解決方案的詳細(xì)內(nèi)容,更多關(guān)于React常見錯(cuò)誤的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • react組件從搭建腳手架到在npm發(fā)布的步驟實(shí)現(xiàn)

    react組件從搭建腳手架到在npm發(fā)布的步驟實(shí)現(xiàn)

    這篇文章主要介紹了react組件從搭建腳手架到在npm發(fā)布的步驟實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-01-01
  • 阿里低代碼框架lowcode-engine設(shè)置默認(rèn)容器詳解

    阿里低代碼框架lowcode-engine設(shè)置默認(rèn)容器詳解

    這篇文章主要為大家介紹了阿里低代碼框架lowcode-engine設(shè)置默認(rèn)容器詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • react-native ListView下拉刷新上拉加載實(shí)現(xiàn)代碼

    react-native ListView下拉刷新上拉加載實(shí)現(xiàn)代碼

    本篇文章主要介紹了react-native ListView下拉刷新上拉加載實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • react批量引入svg圖標(biāo)的方法

    react批量引入svg圖標(biāo)的方法

    這篇文章主要介紹了react批量引入svg圖標(biāo)的方法,在批量引入之前,我們需要安裝一個(gè)包并配置到typescript.json文件中,需要的朋友可以參考下
    2024-03-03
  • react+ant.d添加全局loading方式

    react+ant.d添加全局loading方式

    這篇文章主要介紹了react+ant.d添加全局loading方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • React-Native使用Mobx實(shí)現(xiàn)購(gòu)物車功能

    React-Native使用Mobx實(shí)現(xiàn)購(gòu)物車功能

    本篇文章主要介紹了React-Native使用Mobx實(shí)現(xiàn)購(gòu)物車功能,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-09-09
  • React中條件渲染的常見方法總結(jié)

    React中條件渲染的常見方法總結(jié)

    條件渲染在React開發(fā)中非常重要的功能,它允許開發(fā)人員根據(jù)條件控制渲染的內(nèi)容,在創(chuàng)建動(dòng)態(tài)和交互式用戶界面方面發(fā)揮著至關(guān)重要的作用,本文總結(jié)了常用的的條件渲染方法,需要的朋友可以參考下
    2024-01-01
  • React高階組件使用詳細(xì)介紹

    React高階組件使用詳細(xì)介紹

    高階組件就是接受一個(gè)組件作為參數(shù)并返回一個(gè)新組件(功能增強(qiáng)的組件)的函數(shù)。這里需要注意高階組件是一個(gè)函數(shù),并不是組件,這一點(diǎn)一定要注意,本文給大家分享React高階組件使用小結(jié),一起看看吧
    2023-01-01
  • react-router實(shí)現(xiàn)跳轉(zhuǎn)傳值的方法示例

    react-router實(shí)現(xiàn)跳轉(zhuǎn)傳值的方法示例

    這篇文章主要給大家介紹了關(guān)于react-router實(shí)現(xiàn)跳轉(zhuǎn)傳值的相關(guān)資料,文中給出了詳細(xì)的示例代碼,對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面跟著小編一起來(lái)學(xué)習(xí)學(xué)習(xí)吧。
    2017-05-05
  • React?中hooks之?React.memo?和?useMemo用法示例總結(jié)

    React?中hooks之?React.memo?和?useMemo用法示例總結(jié)

    React.memo是一個(gè)高階組件,用于優(yōu)化函數(shù)組件的性能,通過(guò)記憶組件渲染結(jié)果來(lái)避免不必要的重新渲染,合理使用React.memo和useMemo可以顯著提升React應(yīng)用的性能,本文介紹React?中hooks之?React.memo?和?useMemo用法總結(jié),感興趣的朋友一起看看吧
    2025-01-01

最新評(píng)論

和龙市| 迁安市| 台中市| 永胜县| 通州区| 嘉定区| 阜阳市| 阿巴嘎旗| 宁强县| 屏东县| 万全县| 西乡县| 大悟县| 黄浦区| 桓仁| 高尔夫| 绥江县| 梨树县| 霍城县| 长沙县| 民乐县| 花垣县| 刚察县| 唐山市| 建始县| 贵南县| 河西区| 云和县| 来凤县| 上虞市| 芦山县| 讷河市| 鲁山县| 林芝县| 葵青区| 夏津县| 耿马| 汉寿县| 贞丰县| 嘉黎县| 甘泉县|