日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

蛻變之始,useEffect 最后一種用法

來源: 責編: 時間:2024-01-02 09:28:32 201觀看
導讀在 React 官方文檔中,對于 useEffect 有這樣一句描述:Effects are an escape hatch from the React paradigm。這句話怎么理解呢?我們要結合前面的哲學部分進行思考。React 開發指導思想是數據驅動 UI,因此在 React 程序

hgz28資訊網——每日最新資訊28at.com

在 React 官方文檔中,對于 useEffect 有這樣一句描述:Effects are an escape hatch from the React paradigm。hgz28資訊網——每日最新資訊28at.com

這句話怎么理解呢?我們要結合前面的哲學部分進行思考。React 開發指導思想是數據驅動 UI,因此在 React 程序中,我們總是會思考如何設計與 UI 保持一致的數據,把解決問題的重心放在數據邏輯上。hgz28資訊網——每日最新資訊28at.com

但是這樣的思路并不能應對所有場景。在一些特殊的場景里,我們需要跳出數據驅動 UI 的解題思路,例如為了避免出現性能瓶頸,在高頻率的事件監聽中,我們會選擇直接使用原生 DOM 節點來解決問題。hgz28資訊網——每日最新資訊28at.com

意思就是說,如果你想要跳出 React 的環境使用其他的方式開發,可以把 effect 作為一個對外接口。hgz28資訊網——每日最新資訊28at.com

官方文檔也對此有進一步的解釋:hgz28資訊網——每日最新資訊28at.com

They let you “step outside” of React and synchronize your components with some external system like a non-React widget, network, or the browser DOMhgz28資訊網——每日最新資訊28at.com

這樣的 escape hatch 給 React 帶來了極大的靈活性。在一個復雜的項目中,我們可以使用 React 解決一部分邏輯,然后使用別的更合適的方案解決另外的問題,這樣的靈活性提高了 React 項目的上限。這也是 React 能參與到類似于 Figma 這樣龐大、復雜、對性能要求極高的項目中去的原因。hgz28資訊網——每日最新資訊28at.com

hgz28資訊網——每日最新資訊28at.com

Figmahgz28資訊網——每日最新資訊28at.com

一、如何運用

useEffect 第二個參數為一個數組,當我們傳入的參數為一個空數組時,表示 effect 僅會在組件首次渲染完成時執行。hgz28資訊網——每日最新資訊28at.com

useEffect(effect, [])

只要我們確保當前組件在程序運行過程中相對穩定,不會隨時被刪除,那么我們就可以在 effect 中獲取原生 DOM 節點,并添加綁定事件,回歸到原生 DOM 開發思路中去,你甚至可以在這里繼續使用 jQuery。hgz28資訊網——每日最新資訊28at.com

我們也可以在這里放心使用百度地圖 javaScript sdk,從而完整的在 react 項目中嵌入百度地圖。hgz28資訊網——每日最新資訊28at.com

function App() {  // ...  useEffect(() => {    var mp = new BMapGL.Map('map');     mp.centerAndZoom(new BMapGL.Point(121.491, 31.233), 11);   }, [])  // ...}

或者與 echarts 結合使用。hgz28資訊網——每日最新資訊28at.com

function App() {  const main = useRef(null)  useEffect(() => {    var myChart = echarts.init(main.current);    // 指定圖表的配置項和數據    var option = {      title: {        text: 'ECharts 入門示例'      },      tooltip: {},      legend: {        data: ['銷量']      },      xAxis: {        data: ['襯衫', '羊毛衫', '雪紡衫', '褲子', '高跟鞋', '襪子']      },      yAxis: {},      series: [        {          name: '銷量',          type: 'bar',          data: [5, 20, 36, 10, 10, 20]        }      ]    };    // 使用剛指定的配置項和數據顯示圖表。    myChart.setOption(option);  }, [])  return (    <div id="main" ref={main}></div>  )}

其他的例子還有很多,我們這里使用一個案例來進一步感受 React 與原生 DOM 開發結合的方式。hgz28資訊網——每日最新資訊28at.com

二、需求

在長頁面滾動的過程中,我們常常會在頁面的頂部或者旁邊,放一個標識組件來告訴用戶頁面已經滾動到什么位置了。hgz28資訊網——每日最新資訊28at.com

hgz28資訊網——每日最新資訊28at.com

在滾動的過程中,當前選中狀態會自動變化到對應的位置。接下來我們思考一下這樣的功能應該如何實現。hgz28資訊網——每日最新資訊28at.com

本案例具體要實現的效果如圖:hgz28資訊網——每日最新資訊28at.com

hgz28資訊網——每日最新資訊28at.com

三、實現

實現原理比較簡單,我們只需要判斷每個元素什么時候應該出現在屏幕中即可。對于原生 DOM 而言,我們可以使用 getBoundingClientRect 來獲取元素對象在可視區域中的位置信息。hgz28資訊網——每日最新資訊28at.com

本案例中的判斷規則非常簡單粗暴,因此當同屏出現兩個目標元素時會存在規則沖突,實踐中的規則設計會更細致一些,判斷邏輯也會更復雜。hgz28資訊網——每日最新資訊28at.com

React 提供了 useRef 來獲取真實 DOM 對象。hgz28資訊網——每日最新資訊28at.com

const n1 = useRef<HTMLDivElement>(null)... <div ref={n1}></div>

本案例中的主要內容為我們前面章節中搜索的 demo,因此每個 demo 都是使用 Block 組件來包裹布局。hgz28資訊網——每日最新資訊28at.com

<Block className={s.container} title={td.title} desc={td.desc}>  <div className={r.flex}>    <input      className={s.input}      placeholder="請輸入您要搜索的內容"      onChange={(e) => setParam(e.target.value)}    />  </div>  <List    list={list}    loading={loading}    error={error}    renderItem={(item) => (      <div key={item} className={s.item}>{item}</div>    )}  /></Block>

但是因為 Block 并沒有針對 ref 進行支持,因此我們可以在外面額外套一個 div 作為目標元素。hgz28資訊網——每日最新資訊28at.com

import Normal from './search/Normal'... <div ref={n1}>  <Normal /></div>

在頁面滾動的過程中,目標元素相對于可視區域的位置會隨時發生變化。因此我們可以在 effect 中添加 document 的滾動事件監聽。hgz28資訊網——每日最新資訊28at.com

useEffect(() => {  document.addEventListener('scroll', () => {    ...  })}, [])

設計一個 state 狀態用來對應選中狀態。hgz28資訊網——每日最新資訊28at.com

const [current, setCurrent] = useState(0)...<div className={current == 0 ? `${s.item} ${s.active}` : s.item}>案例一</div>

這樣,我們只需要在滾動過程中,不停的判斷每個目標元素和視口的相對位置,當符合條件的目標元素出現在視口時,就設置 current 為對應的值,功能就實現了。hgz28資訊網——每日最新資訊28at.com

useEffect(() => {  document.addEventListener('scroll', () => {    const n1y = n1.current?.getBoundingClientRect().y    const n2y = n2.current?.getBoundingClientRect().y    const n3y = n3.current?.getBoundingClientRect().y    const n4y = n4.current?.getBoundingClientRect().y    const n5y = n5.current?.getBoundingClientRect().y    if (n1y > 0 && n1y < window.innerHeight) {      setCurrent(0)    }    if (n2y > 0 && n2y < window.innerHeight) {      setCurrent(1)    }    if (n3y > 0 && n3y < window.innerHeight) {      setCurrent(2)    }    if (n4y > 0 && n4y < window.innerHeight) {      setCurrent(3)    }    if (n5y > 0 && n5y < window.innerHeight) {      setCurrent(4)    }  })}, [])

當我們使用 ref 獲取真實 DOM 時,ref 可能會為 null,但是由于 effect 在組件渲染完成之后執行,此時必定能獲取到真實 DOM,因此我們使用 ?. 跳過了為 null 的判斷。hgz28資訊網——每日最新資訊28at.com

const n1y = n1.current?.getBoundingClientRect().y

完整代碼如下:hgz28資訊網——每日最新資訊28at.com

import { useEffect, useRef, useState } from 'react'import Normal from './search/Normal'import Normal2 from './search/Normal2'import Normal3 from './search/Normal3'import Normal4 from './search/Normal4'import Normal5 from './search/Normal5'import s from './style.module.scss'export default function EffectDemo() {  const [current, setCurrent] = useState(0)  const n1 = useRef<HTMLDivElement>(null)  const n2 = useRef<HTMLDivElement>(null)  const n3 = useRef<HTMLDivElement>(null)  const n4 = useRef<HTMLDivElement>(null)  const n5 = useRef<HTMLDivElement>(null)  useEffect(() => {    document.addEventListener('scroll', () => {      const n1y = n1.current?.getBoundingClientRect().y as number      const n2y = n2.current?.getBoundingClientRect().y as number      const n3y = n3.current?.getBoundingClientRect().y as number      const n4y = n4.current?.getBoundingClientRect().y as number      const n5y = n5.current?.getBoundingClientRect().y as number      if (n1y > 0 && n1y < window.innerHeight) {        setCurrent(0)      }      if (n2y > 0 && n2y < window.innerHeight) {        setCurrent(1)      }      if (n3y > 0 && n3y < window.innerHeight) {        setCurrent(2)      }      if (n4y > 0 && n4y < window.innerHeight) {        setCurrent(3)      }      if (n5y > 0 && n5y < window.innerHeight) {        setCurrent(4)      }    })  }, [])  return (    <div>      <div className={s.nav}>        <div className={current == 0 ? `${s.item} ${s.active}` : s.item}>案例一</div>        <div className={current == 1 ? `${s.item} ${s.active}` : s.item}>案例二</div>        <div className={current == 2 ? `${s.item} ${s.active}` : s.item}>案例三</div>        <div className={current == 3 ? `${s.item} ${s.active}` : s.item}>案例四</div>        <div className={current == 4 ? `${s.item} ${s.active}` : s.item}>案例五</div>      </div>      <div ref={n1}>        <Normal />      </div>      <div ref={n2}>        <Normal2 />      </div>            <div ref={n3}>        <Normal3 />      </div>      <div ref={n4}>        <Normal4 />      </div>            <div ref={n5}>        <Normal5 />      </div>          </div>  )}

四、總結

大量的初級框架開發者被困在「試圖讓框架解決所有問題」的思想牢籠里,認為學會了框架似乎就完事了。然而事實上,靈活運用 React 的 escape hatch 特性是成為 React 高手的標志之一,他在指引學習者不要把學習目標局限在 React 中,這是我們蛻變的開始。hgz28資訊網——每日最新資訊28at.com

不要試圖讓 React 解決所有問題,讓他做擅長的事情。hgz28資訊網——每日最新資訊28at.com

接下來我們思考兩個問題,一個問題是,在上面的案例中,我并沒有移除事件綁定,這樣的行為是否會造成內存泄露?第二個問題,我們期望封裝一個圖片組件,該組件需要支持懶加載的優化特性:只有當圖片內容進入到可視區域時,圖片才開始加載,這樣的圖片組件應該如何封裝?hgz28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-55008-0.html蛻變之始,useEffect 最后一種用法

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: Go測試的20個實用建議,你采納了嗎?

下一篇: Vue.js 3.4版本發布:解析速度提升兩倍,雙向綁定等新功能

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 合江县| 白水县| 建宁县| 封开县| 紫金县| 邵阳县| 辽中县| 南昌县| 交城县| 石首市| 沁阳市| 松原市| 开鲁县| 盐亭县| 昌图县| 泰宁县| 和政县| 铜陵市| 包头市| 舞阳县| 全州县| 英吉沙县| 密云县| 九台市| 崇阳县| 壶关县| 阳信县| 松滋市| 横峰县| 大埔区| 乌鲁木齐县| 大英县| 新乐市| 杭州市| 银川市| 达拉特旗| 吉木乃县| 定远县| 广水市| 弋阳县| 建水县|