日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

react取消捕获_React 面试指南 (上)

發布時間:2024/4/20 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 react取消捕获_React 面试指南 (上) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

使用 React 進行項目開發也有好幾個項目了,趁著最近有空來對 React 的知識做一個簡單的復盤。

完整目錄概覽

  • React 是單向數據流還是雙向數據流?它還有其他特點嗎?
  • setState
    • React 通過什么方式來更新數據
    • React 不能直接修改 State 嗎?
    • setState 是同步還是異步的?
    • setState 小測
  • React 生命周期
    • constructor (構造函數)
    • static getDerivedStateFromProps
    • shouldComponentUpdate
    • render
    • getSnapshotBeforeUpdate
    • componentDidMount
    • componentDidUpdate
    • componentWillUnmount
    • 生命周期階段
    • 其他生命周期
  • React 組件通信
    • React.Context 怎么使用
  • 函數組件是什么?與類組件有什么區別?
  • Hooks
    • Hook vs class
    • Hooks 的使用
    • 自定義 Hook 的使用
    • Hook 使用約束
    • class 組件與 Hook 之間的映射與轉換
    • 生命周期
      • Hooks 沒有實現的生命周期鉤子
      • 轉換實例變量
      • 強制更新 Hook 組件
      • 獲取舊的 props 和 state
  • 受控組件與非受控組件的區別
  • Portals 是什么?

React 是單向數據流還是雙向數據流?它還有其他特點嗎?

React 是單向數據流,數據是從上向下流。它的其他主要特點時:

  • 數據驅動視圖
  • 聲明式編寫 UI
  • 組件化開發

React 通過什么方式來更新數據

React 是通過 setState 來更新數據的。調用多個 setState 不會立即更新數據,而會批量延遲更新后再將數據合并。

除了 setState 外還可以使用 forceUpdate 跳過當前組件的 shouldComponentUpdate diff,強制觸發組件渲染(避免使用該方式)。

React 不能直接修改 State 嗎?

  • 直接修改 state 不會觸發組件的渲染。
  • 若直接修改 state 引用的值,在實際使用時會導致錯誤的值出現
  • 修改后的 state 可能會被后續調用的 setState 覆蓋
  • setState 是同步還是異步的?

    出于性能的考慮,React 可能會把多個 setState 合并成一個調用。

    React 內有個 batchUpdate(批量更新) 的機制,在 React 可以控制的區域 (如組件生命周期、React 封裝的事件處理器) 設置標識位 isBatchingUpdate 來決定是否觸發更新。

    比如在 React 中注冊的 onClick 事件或是 componentDidMount 中直接使用 setState 都是異步的。若想拿到觸發更新后的值,可以給 setState 第二個參數傳遞一個函數,該函數在數據更新后會觸發的回調函數,函數的參數就是更新后最新的值。

    不受 React 控制的代碼快中使用 setState 是同步的,比如在 setTimeout 或是原生的事件監聽器中使用。

    setState 小測

    輸出以下結果:

    componentDidMount() {this.setState({ count: this.state.count + 1 });console.log("1 -->", this.state.count);this.setState({ count: this.state.count + 1 });console.log("2 -->", this.state.count);setTimeout(() => {this.setState({ count: this.state.count + 1 });console.log("3 -->", this.state.count);}, 0);setTimeout(() => {this.setState({ count: this.state.count + 1 });console.log("4 -->", this.state.count);}, 0); }

    輸出結果為:

    1 --> 0 2 --> 0 3 --> 2 4 --> 3

    解答: 調用 setState 后不會立即更新 state,開頭兩次調用會被異步合并調用,因此只有一次調用。一輪事件循環結束后,調用第 3、4 次 setState。由于在 setTimeout 中調用是同步更新的,因此都能正常的疊加數據。

    React 生命周期

    React 的生命周期主要是指組件在特定階段會執行的函數。以下是 class 組件的部分生命周期圖譜:

    React 生命周期速查圖

    從上圖可以看出:React 的生命周期按照類型劃分,可分為 掛載時(Mounting)、更新時(Updating)、卸載時(Unmounting) 。圖中的生命周期函數效果如下:

    constructor (構造函數)

    • 觸發條件: 組件初始化時
    • 是否可以使用 setState: X
    • 使用場景: 初始化 state 或者對方法綁定 this

    static getDerivedStateFromProps

    Tips: 不常用方法
    • 觸發條件: 調用 render 函數之前
    • 是否可以使用 setState: X
    • 函數行為: 函數可以返回一個對象用于更新組件內部的 state 數據,若返回 null 則什么都不更新。
    • 使用場景: 用于 state 依賴 props 的情況,也就是狀態派生。值得注意的是派生 state 會導致代碼冗余,并使組件難以維護。

    shouldComponentUpdate

    Tips: 不常用方法
    • 觸發條件: 當 props/state 發生變化
    • 是否可以使用 setState: X
    • 函數行為: 函數的返回值決定組件是否觸發 render,返回值為 true 則觸發渲染,反之則阻止渲染。(組件內不寫該函數的話,則調用默認函數。默認函數只會返回 true,即只要 props/state 發生變化,就更新組件)
    • 使用場景: 組件的性能優化,僅僅是淺比較 props 和 state 的變化的話,可以使用內置的 PureComponent 來代替 Component 組件。

    render

    • 觸發條件: 渲染組件時
    • 是否可以使用 setState: X
    • 函數行為: 函數的返回值決定視圖的渲染效果
    • 使用場景: class 組件中唯一必須要實現的生命周期函數。

    getSnapshotBeforeUpdate

    Tips: 不常用方法
    • 觸發條件: 在最近一次渲染輸出(提交到 DOM 節點)之前調用
    • 是否可以使用 setState: X
    • 函數行為: 函數的返回值將傳入給 componentDidUpdate 第三個參數中。若只實現了該函數,但沒有使用 componentDidUpdate 的話,React 將會在控制臺拋出警告
    • 使用場景: 可以在組件發生更改之前從 DOM 中捕獲一些信息(例如,列表的滾動位置)

    componentDidMount

    • 觸發條件: 組件掛載后(插入 DOM 樹中)立即調用
    • 是否可以使用 setState: Y (可以直接調用,但會觸發額外渲染)
    • 使用場景: 從網絡請求中獲取數據、訂閱事件等

    componentDidUpdate

    • 觸發條件: 組件更新完畢后(首次渲染不會觸發)
    • 是否可以使用 setState: Y (更新語句須放在條件語句中,不然可能會造成死循環)
    • 使用場景: 對比新舊值的變化,進而判斷是否需要發送網絡請求。比如監聽路由的變化

    componentWillUnmount

    • 觸發條件: 組件卸載及銷毀之前直接調用
    • 是否可以使用 setState: X
    • 使用場景: 清除 timer,取消網絡請求或清除在 componentDidMount 中創建的訂閱等

    生命周期階段

    針對 React 生命周期中函數的調用順序,筆者寫了一個簡易的 Demo 用于演示: React 生命周期示例

    React 組件掛載階段先后會觸發 constuctor、static getDerivedStateFromProps、render、componentDidMount 函數。若 render 函數內還有子組件存在的話,則會進一步遞歸:

    [Parent]: constuctor [Parent]: static getDerivedStateFromProps [Parent]: render [Children]: constuctor [Children]: static getDerivedStateFromProps [Children]: render [Children]: componentDidMount [Children]: 掛載階段結束! [Parent]: componentDidMount [Parent]: 掛載階段結束!

    React 組件更新階段主要是組件的 props 或 state 發生變化時觸發。若組件內還子組件,則子組件會判斷是否也需要觸發更新。默認情況下 component 組件是只要父組件發生了變化,子組件也會跟著變化。以下是更新父組件 state 數據時所觸發的生命周期函數:

    [Parent]: static getDerivedStateFromProps [Parent]: shouldComponentUpdate [Parent]: render [Children]: static getDerivedStateFromProps [Children]: shouldComponentUpdate [Children]: render [Children]: getSnapshotBeforeUpdate [Parent]: getSnapshotBeforeUpdate [Children]: componentDidUpdate [Children]: 更新階段結束! [Parent]: componentDidUpdate [Parent]: 更新階段結束!

    值得注意的是: 在本例 Demo 中沒有給子組件傳參,但子組件也觸發了渲染。但從應用的角度上考慮,既然你子組件沒有需要更新的東西,那就沒有必要觸發渲染吧?

    因此 Component 組件上可以使用 shouldComponentUpdate 或者將 Component 組件替換為 PureComponment 組件來做優化。在生命周期圖中也可以看到: shouldComponentUpdate 返回 false 時,將不再繼續觸發下面的函數。

    有時你可能在某些情況下想主動觸發渲染而又不被 shouldComponentUpdate 阻止渲染該怎么辦呢?可以使用 force-Update() 跳過 shouldComponentUpdate 的 diff,進而渲染視圖。(需要使用強制渲染的場景較少,一般不推薦這種方式進行開發)

    React 組件銷毀階段也沒啥好說的了。父組件先觸發銷毀前的函數,再逐層向下觸發:

    [Parent]: componentWillUnmount [Parent]: 卸載階段結束! [Children]: componentWillUnmount [Children]: 卸載階段結束!

    其他生命周期

    除了上圖比較常見的生命周期外,還有一些過時的 API 就沒有額外介紹了。因為它們可能在未來的版本會被移除。

    • UNSAFE_componentWillMount()
    • UNSAFE_componentWillUpdate()
    • UNSAFE_componentWillReceiveProps()

    當渲染過程,生命周期,或子組件的構造函數中拋出錯誤時,會調用如下方法:

    • static getDerivedStateFromError()
    • componentDidCatch()

    React 組件通信

  • 父組件通過 props 給子組件傳遞數據。子組件通過觸發父組件提供的回調函數來給父組件傳遞消息或數據
  • React.Context 可以跨層級組件共享數據
  • 自定義事件
  • 引入 Redux/Mobx 之類的狀態管理器
  • React.Context 怎么使用

    Context 可以共享對于組件樹而言是全局的數據,比如全局主題、首選語言等。使用方式如下:

  • React.createContext 函數用于生成 Context 對象。可以在創建時給 Context 設置默認值:
  • const ThemeContext = React.createContext('light');

    2. Context 對象中有一個 Provider(提供者) 組件,Provider 組件接受一個 value 屬性用以將數據傳遞給消費組件。

    <ThemeContext.Provider value="dark"><page /> </ThemeContext.Provider>

    3. 獲取 Context 提供的值可以通過 contextType 或者 Consumer(消費者) 組件中獲取。contextType 只能用于類組件,并且只能掛載一個 Context:

    class MyClass extends React.Component {componentDidMount() {let value = this.context;/* 在組件掛載完成后,使用 MyContext 的值執行一些有副作用的操作 */}render() {let value = this.context;/* 基于 MyContext 的值進行渲染 */} } MyClass.contextType = MyContext;

    若想給組件掛載多個 Context, 或者在函數組件內使用 Context 可以使用 Consumer 組件:

    <ThemeContext.Consumer>{theme => (<UserContext.Consumer>{user => (<ProfilePage user={user} theme={theme} />)}</UserContext.Consumer>)}</ThemeContext.Consumer>

    Context 通常適用于傳遞較為簡單的數據信息,若數據太過復雜,還是需要引入狀態管理(Redux/Mbox)。

    函數組件是什么?與類組件有什么區別?

    函數組件本質上是一個純函數,它接受 props 屬性,最后返回 JSX。

    與類組件的差別在于: 它沒有實例、不能通過 extends 繼承于其他方法、也沒有生命周期和 state。以前函數組件常作為無狀態組件,React 16.8+ 可以引入 Hooks 為函數組件支持狀態和副作用操作。

    Hook vs class

    類組件的不足:

    • 狀態邏輯復用難,缺少復用機制。渲染屬性和高階組件導致層級冗余。
    • 復雜組件變得難以理解。
    • this 指向令人困擾。

    Hooks 的優點:

    • 自定義 Hook 方便復用狀態邏輯
    • 副作用的關注點分離
    • 函數組件沒有 this 問題

    Hooks 現有的不足:

    • 不能完全取代 class 組件的生命周期,部分不常用的生命周期暫時沒有實現。
    • Hooks 的運作方式帶來了一定的學習成本,需要轉換現有的編程思維,增加了心智負擔。

    Hooks 的使用

    描述 Hooks 有哪些常用的方法和大致用途
  • useState: 使函數組件支持設置 state 數據,可用于代替類組件的 constructor 函數。
  • useEffect: 使函數組件支持操作副作用 (effect) 的能力,Hook 第二個參數是 effect 的依賴項。當依賴項是空時,effect 函數僅會在組件掛載后執行一遍。若有一個或多個依賴項時,只要任意一個依賴項發生變化,就會觸發 effect 函數的執行。effect 函數里可以做一些如獲取頁面數據、訂閱事件等操作。
  • 除此之外,useEffect 還可以返回一個函數用于做清除操作,這個清除操作時可選的。常用于清理訂閱事件、DOM 事件等。

    // 綁定 DOM 事件 useEffect(() => {document.addEventListener('click', handleClick);// useEffect 回調函數的返回值是函數的話,當組件卸載時會執行該函數// 若沒有需要清除的東西,則可以忽略這一步驟return () => {document.removeEventListener('click', handleClick);}; }, [handleClick]);}, [handleClick]); ```

    3. useLayoutEffect: useEffect 的 effect 執行的時機是在瀏覽器完成布局和繪制之后會延遲調用。若想要 DOM 變更的同時同步執行 effect 的話可以使用 useLayoutEffect。它們之間只是執行的時機不同,其他都一樣。

    4. useContext: 接收一個 Context 對象,并返回 Context 的當前值。相當于類組件的 static contextType = MyContext。

    5. useReducer 是 useState 的代替方案,它的工作方式有點類似于 Redux,通過函數來操作 state。適合 state 邏輯較為復雜且包含多個子值,或是新的 state 依賴于舊的 state 的場景。

    6. useMemo 主要用于性能優化,它可以緩存變量的值,避免每次組件更新后都需要重復計算值。

    7. useCallbck 用于緩存函數,避免函數被重復創建,它是 useMemo 的語法糖。useCallback(fn, deps) 的效果相當于是 useMemo(() => fn, deps)。

    自定義 Hook 的使用

    自定義 Hook 的命名規則是以 use 開頭的函數,比如 useLocalStorage 就符合自定義 Hook 的命名規范。 使用自定義 Hook 的場景有很多,如表單處理、動畫、訂閱聲明、定時器等等可復用的邏輯都能通過自定義 Hook 來抽象實現。

    在自定義 Hook 中,可以使用 Hooks 函數將可復用的邏輯和功能提取出來,并將內部的 state 或操作的方法從自定義 Hook 函數中返回出來。函數組件使用時就可以像調用普通函數一祥調用自定義 Hook 函數, 并將自定義 Hook 返回的 state 和操作方法通過解構保存到變量中。

    下面是 useLocalStorage 的實現,它將 state 同步到本地存儲,以使其在頁面刷新后保持不變。 用法與 useState 相似,不同之處在于我們傳入了本地存儲鍵,以便我們可以在頁面加載時默認為該值,而不是指定的初始值。

    import { useState } from 'react';// Usage function App() {// Similar to useState but first arg is key to the value in local storage.const [name, setName] = useLocalStorage('name', 'Bob');return (<div><inputtype="text"placeholder="Enter your name"value={name}onChange={e => setName(e.target.value)}/></div>); }// Hook function useLocalStorage(key, initialValue) {// State to store our value// Pass initial state function to useState so logic is only executed onceconst [storedValue, setStoredValue] = useState(() => {try {// Get from local storage by keyconst item = window.localStorage.getItem(key);// Parse stored json or if none return initialValuereturn item ? JSON.parse(item) : initialValue;} catch (error) {// If error also return initialValueconsole.log(error);return initialValue;}});// Return a wrapped version of useState's setter function that ...// ... persists the new value to localStorage.const setValue = value => {try {// Allow value to be a function so we have same API as useStateconst valueToStore =value instanceof Function ? value(storedValue) : value;// Save statesetStoredValue(valueToStore);// Save to local storagewindow.localStorage.setItem(key, JSON.stringify(valueToStore));} catch (error) {// A more advanced implementation would handle the error caseconsole.log(error);}};return [storedValue, setValue]; }

    注意: 自定義 Hook 函數在定義時,也可以使用另一個自定義 Hook 函數。

    Hook 使用約束

  • 只能在函數組件最頂層調用 Hook,不能在循環、條件判斷或子函數中調用。
  • 只能在函數組件或者是自定義 Hook 函數中調用,普通的 js 函數不能使用。
  • class 組件與 Hook 之間的映射與轉換

    函數組件相比 class 組件會缺少很多功能,但大多可以通過 Hook 的方式來實現。

    生命周期

    • constructor:class 組件的構造函數一般是用于初始化 state 數據或是給事件綁定 this 指向的。函數組件內沒有 this 指向的問題,因此可以忽略。而 state 可以通過 useState/useReducer 來實現。
    • getDerivedStateFromProps:getDerivedStateFromProps 一般用于在組件 props 發生變化時派生 state。Hooks 實現同等效果如下:

    ``` jsx function ScrollView({row}) { const [isScrollingDown, setIsScrollingDown] = useState(false); const [prevRow, setPrevRow] = useState(null);

    function ScrollView({row}) {const [isScrollingDown, setIsScrollingDown] = useState(false);const [prevRow, setPrevRow] = useState(null);if (row !== prevRow) {// Row 自上次渲染以來發生過改變。更新 isScrollingDown。setIsScrollingDown(prevRow !== null && row > prevRow);setPrevRow(row);}return `Scrolling down: ${isScrollingDown}`; }
    • shouldComponentUpdate: 使用 React.memo 應用到函數組件中后,當 props 發生變化時,會對 props 的新舊值進行前對比,相當于是 PureComponent 的功能。如果你還想自己定義比較函數的話,可以給 React.memo 的第二個參數傳一個函數,若函數返回 true 則跳過更新。
    const Button = React.memo((props) => {return <button>{props.text}</button>});
    • render: 函數組件本身就是一個 render 函數。
    • componentDidMount / componentDidUpdate / componentWillUnmount:

    useEffect 第二個參數的依賴項為空時,相當于 componentDidMount,組件掛載后只會執行一次。每個 useEffect 返回的函數相當于是 componentWillUnmount 同等效果的操作。若有依賴,則 effect 函數相當于是 componentDidUpdate:

    // 沒有依賴項,僅執行一次 useEffect(() => {const subscription = props.source.subscribe();// 相當于 componentWillUnmountreturn () => {subscription.unsubscribe();}; }, []);// 若有依賴項,相當于 componentDidUpdate // 當 page 發生變化時會觸發 effect 函數 useEffect(() => {fetchList({ page }); }, [page]);

    Hooks 沒有實現的生命周期鉤子

    • getSnapshotBeforeUpdate
    • getDerivedStateFromError
    • componentDidCatch

    轉換實例變量

    使用 useRef 設置可變數據。

    強制更新 Hook 組件

    設置一個沒有實際作用的 state,然后強制更新 state 的值觸發渲染。

    const Todo = () => {// 使用 useState,用隨機數據更新也行const [ignored, forceUpdate] = useReducer(x => x + 1, 0);function handleClick() {forceUpdate();}return <button click={handleClick}>強制更新組件</button> }

    獲取舊的 props 和 state

    可以通過 useRef 來保存數據,因為渲染時不會覆蓋掉可變數據。

    function Counter() {const [count, setCount] = useState(0);const prevCountRef = useRef();useEffect(() => {prevCountRef.current = count;}, []);const prevCount = prevCountRef.current;return <h1>Now: {count}, before: {prevCount}</h1>; }

    受控組件與非受控組件的區別

    受控組件主要是指表單的值受到 state 的控制,它需要自行監聽 onChange 事件來更新 state。

    由于受控組件每次都要編寫事件處理器才能更新 state 數據、可能會有點麻煩,React 提供另一種代替方案是非受控組件。

    非受控組件將真實數據儲存在 DOM 節點中,它可以為表單項設置默認值,不需要手動更新數據。當需要用到表單數據時再通過 ref 從 DOM 節點中取出數據即可。

    注意: 多數情況下React 推薦編寫受控組件。

    擴展資料: 受控和非受控制使用場景的選擇

    Portals 是什么?

    Portals 就像個傳送門,它可以將子節點渲染到存在于父組件以外的 DOM 節點的方案。

    比如 Dialog 是一個全局組件,按照傳統渲染組件的方式,Dialog 可能會受到其容器 css 的影響。因此可以使用 Portals 讓組件在視覺上渲染到 <body> 中,使其樣式不受 overflow: hidden 或 z-index 的影響。


    • 下一篇文章: React 面試指南 (下)
    • 原文出自: React 知識回顧 (使用篇) | Anran758's blog
    • 前端面試筆記: front-end-lab

    總結

    以上是生活随笔為你收集整理的react取消捕获_React 面试指南 (上)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。