日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

2022react高頻面試題有哪些

作者:beifeng11996 更新時間: 2022-09-25 編程語言

(在構造函數中)調用 super(props) 的目的是什么

super() 被調用之前,子類是不能使用 this 的,在 ES2015 中,子類必須在 constructor 中調用 super()。傳遞 propssuper() 的原因則是便于(在子類中)能在 constructor 訪問 this.props。

你對【單一數據源】有什么理解

redux使用 store將程序的整個狀態存儲在同一個地方,因此所有組件的狀態都存儲在 Store 中,并且它們從 Store 本身接收更新。單一狀態樹可以更容易地跟蹤隨時間的變化,并調試或檢查程序

前端react面試題詳細解答

什么是控制組件?

在 HTML 中,表單元素如 <input>、<textarea><select>通常維護自己的狀態,并根據用戶輸入進行更新。當用戶提交表單時,來自上述元素的值將隨表單一起發送。
而 React 的工作方式則不同。包含表單的組件將跟蹤其狀態中的輸入值,并在每次回調函數(例如onChange)觸發時重新渲染組件,因為狀態被更新。以這種方式由 React 控制其值的輸入表單元素稱為受控組件

hooks 為什么不能放在條件判斷里

以 setState 為例,在 react 內部,每個組件(Fiber)的 hooks 都是以鏈表的形式存在 memoizeState 屬性中

image-20210302195353472

update 階段,每次調用 setState,鏈表就會執行 next 向后移動一步。如果將 setState 寫在條件判斷中,假設條件判斷不成立,沒有執行里面的 setState 方法,會導致接下來所有的 setState 的取值出現偏移,從而導致異常發生。

Redux內部原理 內部怎么實現dispstch一個函數的

redux-thunk中間件作為例子,下面就是thunkMiddleware函數的代碼

// 部分轉為ES5代碼,運行middleware函數會返回一個新的函數,如下:
return ({ dispatch, getState }) => {
    // next實際就是傳入的dispatch
    return function (next) {
        return function (action) {
            // redux-thunk核心
            if (typeof action === 'function') { 
                return action(dispatch, getState, extraArgument);
            }
            return next(action);
        };
    };
}

redux-thunk庫內部源碼非常的簡單,允許action是一個函數,同時支持參數傳遞,否則調用方法不變

  • redux創建Store:通過combineReducers函數合并reducer函數,返回一個新的函數combination(這個函數負責循環遍歷運行reducer函數,返回全部state)。將這個新函數作為參數傳入createStore函數,函數內部通過dispatch,初始化運行傳入的combination,state生成,返回store對象
  • redux中間件:applyMiddleware函數中間件的主要目的就是修改dispatch函數,返回經過中間件處理的新的dispatch函數
  • redux使用:實際就是再次調用循環遍歷調用reducer函數,更新state

使用 React Hooks 好處是啥?

首先,Hooks 通常支持提取和重用跨多個組件通用的有狀態邏輯,而無需承擔高階組件或渲染 props 的負擔。Hooks 可以輕松地操作函數組件的狀態,而不需要將它們轉換為類組件。
Hooks 在類中不起作用,通過使用它們,咱們可以完全避免使用生命周期方法,例如 componentDidMount、componentDidUpdate、componentWillUnmount。相反,使用像useEffect這樣的內置鉤子。

組件之間傳值

  • 父組件給子組件傳值

    在父組件中用標簽屬性的=形式傳值

    在子組件中使用props來獲取值

  • 子組件給父組件傳值

    在組件中傳遞一個函數

    在子組件中用props來獲取傳遞的函數,然后執行該函數

    在執行函數的時候把需要傳遞的值當成函數的實參進行傳遞

  • 兄弟組件之間傳值

    利用父組件

    先把數據通過 【子組件】===》【父組件】

    然后在數據通過 【父組件】===〉【子組件】

    消息訂閱

    使用PubSubJs插件

React diff 算法的原理是什么?

實際上,diff 算法探討的就是虛擬 DOM 樹發生變化后,生成 DOM 樹更新補丁的方式。它通過對比新舊兩株虛擬 DOM 樹的變更差異,將更新補丁作用于真實 DOM,以最小成本完成視圖更新。 具體的流程如下:

  • 真實的 DOM 首先會映射為虛擬 DOM;

  • 當虛擬 DOM 發生變化后,就會根據差距計算生成 patch,這個 patch 是一個結構化的數據,內容包含了增加、更新、移除等;

  • 根據 patch 去更新真實的 DOM,反饋到用戶的界面上。

    一個簡單的例子:

import React from 'react'
export default class ExampleComponent extends React.Component {
  render() {
    if(this.props.isVisible) {
       return <div className="visible">visbile</div>;
    }
     return <div className="hidden">hidden</div>;
  }
}

這里,首先假定 ExampleComponent 可見,然后再改變它的狀態,讓它不可見 。映射為真實的 DOM 操作是這樣的,React 會創建一個 div 節點。

<div class="visible">visbile</div>

當把 visbile 的值變為 false 時,就會替換 class 屬性為 hidden,并重寫內部的 innerText 為 hidden。這樣一個生成補丁、更新差異的過程統稱為 diff 算法。

diff算法可以總結為三個策略,分別從樹、組件及元素三個層面進行復雜度的優化:

策略一:忽略節點跨層級操作場景,提升比對效率。(基于樹進行對比)

這一策略需要進行樹比對,即對樹進行分層比較。樹比對的處理手法是非常“暴力”的,即兩棵樹只對同一層次的節點進行比較,如果發現節點已經不存在了,則該節點及其子節點會被完全刪除掉,不會用于進一步的比較,這就提升了比對效率。

策略二:如果組件的 class 一致,則默認為相似的樹結構,否則默認為不同的樹結構。(基于組件進行對比)

在組件比對的過程中:

  • 如果組件是同一類型則進行樹比對;
  • 如果不是則直接放入補丁中。

只要父組件類型不同,就會被重新渲染。這也就是為什么 shouldComponentUpdate、PureComponent 及 React.memo 可以提高性能的原因。

策略三:同一層級的子節點,可以通過標記 key 的方式進行列表對比。(基于節點進行對比)

元素比對主要發生在同層級中,通過標記節點操作生成補丁。節點操作包含了插入、移動、刪除等。其中節點重新排序同時涉及插入、移動、刪除三個操作,所以效率消耗最大,此時策略三起到了至關重要的作用。通過標記 key 的方式,React 可以直接移動 DOM 節點,降低內耗。

在調用setState 之后發生了什么

  • 狀態合并,觸發調和:

    setState函數之后,會將傳入的參數對象與當前的狀態合并,然后出發調用過程

  • 根據新的狀態構建虛擬dom樹

    經過調和過程,react會高效的根據新的狀態構建虛擬DOM樹,準備渲染整個UI頁面

  • 計算新老樹節點差異,最小化渲染

    得倒新的虛擬DOM樹后,會計算出新老樹的節點差異,會根據差異對界面進行最小化渲染

  • 按需更新

    在差異話計算中,react可以相對準確的知道哪些位置發生了改變以及該如何改變,這保證按需更新,而不是宣布重新渲染

hooks父子傳值

父傳子
在父組件中用useState聲明數據
 const [ data, setData ] = useState(false)

把數據傳遞給子組件
<Child data={data} />

子組件接收
export default function (props) {
    const { data } = props
    console.log(data)
}
子傳父
子傳父可以通過事件方法傳值,和父傳子有點類似。
在父組件中用useState聲明數據
 const [ data, setData ] = useState(false)

把更新數據的函數傳遞給子組件
<Child setData={setData} />

子組件中觸發函數更新數據,就會直接傳遞給父組件
export default function (props) {
    const { setData } = props
    setData(true)
}
如果存在多個層級的數據傳遞,也可依照此方法依次傳遞

// 多層級用useContext
const User = () => {
 // 直接獲取,不用回調
 const { user, setUser } = useContext(UserContext);
 return <Avatar user={user} setUser={setUser} />;
};

Hooks可以取代 render props 和高階組件嗎?

通常,render props和高階組件僅渲染一個子組件。React團隊認為,Hooks 是服務此用例的更簡單方法。
這兩種模式仍然有一席之地(例如,一個虛擬的 scroller 組件可能有一個 renderItem prop,或者一個可視化的容器組件可能有它自己的 DOM 結構)。但在大多數情況下,Hooks 就足夠了,可以幫助減少樹中的嵌套。

React 高階組件、Render props、hooks 有什么區別,為什么要不斷迭代

這三者是目前react解決代碼復用的主要方式:

  • 高階組件(HOC)是 React 中用于復用組件邏輯的一種高級技巧。HOC 自身不是 React API 的一部分,它是一種基于 React 的組合特性而形成的設計模式。具體而言,高階組件是參數為組件,返回值為新組件的函數。
  • render props是指一種在 React 組件之間使用一個值為函數的 prop 共享代碼的簡單技術,更具體的說,render prop 是一個用于告知組件需要渲染什么內容的函數 prop。
  • 通常,render props 和高階組件只渲染一個子節點。讓 Hook 來服務這個使用場景更加簡單。這兩種模式仍有用武之地,(例如,一個虛擬滾動條組件或許會有一個 renderltem 屬性,或是一個可見的容器組件或許會有它自己的 DOM 結構)。但在大部分場景下,Hook 足夠了,并且能夠幫助減少嵌套。

(1)HOC 官方解釋∶

高階組件(HOC)是 React 中用于復用組件邏輯的一種高級技巧。HOC 自身不是 React API 的一部分,它是一種基于 React 的組合特性而形成的設計模式。

簡言之,HOC是一種組件的設計模式,HOC接受一個組件和額外的參數(如果需要),返回一個新的組件。HOC 是純函數,沒有副作用。

// hoc的定義
function withSubscription(WrappedComponent, selectData) {
  return class extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        data: selectData(DataSource, props)
      };
    }
    // 一些通用的邏輯處理
    render() {
      // ... 并使用新數據渲染被包裝的組件!
      return <WrappedComponent data={this.state.data} {...this.props} />;
    }
  };

// 使用
const BlogPostWithSubscription = withSubscription(BlogPost,
  (DataSource, props) => DataSource.getBlogPost(props.id));

HOC的優缺點∶

  • 優點∶ 邏輯服用、不影響被包裹組件的內部邏輯。
  • 缺點∶ hoc傳遞給被包裹組件的props容易和被包裹后的組件重名,進而被覆蓋

(2)Render props 官方解釋∶

"render prop"是指一種在 React 組件之間使用一個值為函數的 prop 共享代碼的簡單技術

具有render prop 的組件接受一個返回React元素的函數,將render的渲染邏輯注入到組件內部。在這里,"render"的命名可以是任何其他有效的標識符。

// DataProvider組件內部的渲染邏輯如下
class DataProvider extends React.Components {
     state = {
    name: 'Tom'
  }

    render() {
    return (
        <div>
          <p>共享數據組件自己內部的渲染邏輯</p>
          { this.props.render(this.state) }      </div>
    );
  }
}

// 調用方式
<DataProvider render={data => (
  <h1>Hello {data.name}</h1>
)}/>


由此可以看到,render props的優缺點也很明顯∶

  • 優點:數據共享、代碼復用,將組件內的state作為props傳遞給調用者,將渲染邏輯交給調用者。
  • 缺點:無法在 return 語句外訪問數據、嵌套寫法不夠優雅

(3)Hooks 官方解釋∶

Hook是 React 16.8 的新增特性。它可以讓你在不編寫 class 的情況下使用 state 以及其他的 React 特性。通過自定義hook,可以復用代碼邏輯。

// 自定義一個獲取訂閱數據的hook
function useSubscription() {
  const data = DataSource.getComments();
  return [data];
}
// 
function CommentList(props) {
  const {data} = props;
  const [subData] = useSubscription();
    ...
}
// 使用
<CommentList data='hello' />

以上可以看出,hook解決了hoc的prop覆蓋的問題,同時使用的方式解決了render props的嵌套地獄的問題。hook的優點如下∶

  • 使用直觀;
  • 解決hoc的prop 重名問題;
  • 解決render props 因共享數據 而出現嵌套地獄的問題;
  • 能在return之外使用數據的問題。

需要注意的是:hook只能在組件頂層使用,不可在分支語句中使用。、

哪些方法會觸發 React 重新渲染?重新渲染 render 會做些什么?

(1)哪些方法會觸發 react 重新渲染?

  • setState()方法被調用

setState 是 React 中最常用的命令,通常情況下,執行 setState 會觸發 render。但是這里有個點值得關注,執行 setState 的時候不一定會重新渲染。當 setState 傳入 null 時,并不會觸發 render。

class App extends React.Component {
  state = {
    a: 1
  };

  render() {
    console.log("render");
    return (
      <React.Fragement>
        <p>{this.state.a}</p>
        <button
          onClick={() => {            this.setState({ a: 1 }); // 這里并沒有改變 a 的值          }}        >          Click me        </button>
        <button onClick={() => this.setState(null)}>setState null</button>
        <Child />
      </React.Fragement>
    );
  }
}

  • 父組件重新渲染

只要父組件重新渲染了,即使傳入子組件的 props 未發生變化,那么子組件也會重新渲染,進而觸發 render

(2)重新渲染 render 會做些什么?

  • 會對新舊 VNode 進行對比,也就是我們所說的Diff算法。
  • 對新舊兩棵樹進行一個深度優先遍歷,這樣每一個節點都會一個標記,在到深度遍歷的時候,每遍歷到一和個節點,就把該節點和新的節點樹進行對比,如果有差異就放到一個對象里面
  • 遍歷差異對象,根據差異的類型,根據對應對規則更新VNode

React 的處理 render 的基本思維模式是每次一有變動就會去重新渲染整個應用。在 Virtual DOM 沒有出現之前,最簡單的方法就是直接調用 innerHTML。Virtual DOM厲害的地方并不是說它比直接操作 DOM 快,而是說不管數據怎么變,都會盡量以最小的代價去更新 DOM。React 將 render 函數返回的虛擬 DOM 樹與老的進行比較,從而確定 DOM 要不要更新、怎么更新。當 DOM 樹很大時,遍歷兩棵樹進行各種比對還是相當耗性能的,特別是在頂層 setState 一個微小的修改,默認會去遍歷整棵樹。盡管 React 使用高度優化的 Diff 算法,但是這個過程仍然會損耗性能.

對 React context 的理解

在React中,數據傳遞一般使用props傳遞數據,維持單向數據流,這樣可以讓組件之間的關系變得簡單且可預測,但是單項數據流在某些場景中并不適用。單純一對的父子組件傳遞并無問題,但要是組件之間層層依賴深入,props就需要層層傳遞顯然,這樣做太繁瑣了。

Context 提供了一種在組件之間共享此類值的方式,而不必顯式地通過組件樹的逐層傳遞 props。

可以把context當做是特定一個組件樹內共享的store,用來做數據傳遞。簡單說就是,當你不想在組件樹中通過逐層傳遞props或者state的方式來傳遞數據時,可以使用Context來實現跨層級的組件數據傳遞。

JS的代碼塊在執行期間,會創建一個相應的作用域鏈,這個作用域鏈記錄著運行時JS代碼塊執行期間所能訪問的活動對象,包括變量和函數,JS程序通過作用域鏈訪問到代碼塊內部或者外部的變量和函數。

假如以JS的作用域鏈作為類比,React組件提供的Context對象其實就好比一個提供給子組件訪問的作用域,而 Context對象的屬性可以看成作用域上的活動對象。由于組件 的 Context 由其父節點鏈上所有組件通 過 getChildContext()返回的Context對象組合而成,所以,組件通過Context是可以訪問到其父組件鏈上所有節點組件提供的Context的屬性。

React最新的?命周期是怎樣的?

React 16之后有三個?命周期被廢棄(但并未刪除)

  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

官?計劃在17版本完全刪除這三個函數,只保留UNSAVE_前綴的三個函數,?的是為了向下兼容,但是對于開發者??應該盡量避免使?他們,?是使?新增的?命周期函數替代它們。

?前React16.8+的?命周期分為三個階段,分別是掛載階段、更新階段、卸載階段。

掛載階段:

  • constructor:構造函數,最先被執?,我們通常在構造函數?初始化state對象或者給?定義?法綁定this;
  • getDerivedStateFromProps:static getDerivedStateFromProps(nextProps, prevState),這是個靜態?法,當我們接收到新的屬性想去修改我們state, 可以使?getDerivedStateFromProps
  • render:render函數是純函數,只返回需要渲染的東?,不應該包含其它的業務邏輯,可以返回原?的DOM、React組件、Fragment、Portals、字符串和數字、 Boolean和null等內容;
  • componentDidMount:組件裝載之后調?,此時我們可以獲取到DOM節點并操作,?如對canvas,svg的操作,服務器請求,訂閱都可以寫在這個??,但是記得在componentWillUnmount中取消訂閱;

更新階段:

  • getDerivedStateFromProps: 此?法在更新個掛載階段都可能會調?;
  • shouldComponentUpdate:shouldComponentUpdate(nextProps, nextState),有兩個參數nextProps和nextState,表示新的屬性和變化之后的state,返回?個布爾值,true表示會觸發重新渲染,false表示不會觸發重新渲染,默認返回true,我們通常利?此?命周期來優化React程序性能;
  • render:更新階段也會觸發此?命周期;
  • getSnapshotBeforeUpdate:getSnapshotBeforeUpdate(prevProps, prevState),這個?法在render之后,componentDidUpdate之前調?,有兩個參數prevProps和prevState,表示之前的屬性和之前的state,這個函數有?個返回值,會作為第三個參數傳給componentDidUpdate,如果你不想要返回值,可以返回null,此?命周期必須與componentDidUpdate搭配使?;
  • componentDidUpdate:componentDidUpdate(prevProps, prevState, snapshot),該?法在getSnapshotBeforeUpdate?法之后被調?,有三個參數prevProps,prevState,snapshot,表示之前的props,之前的state,和snapshot。第三個參數是getSnapshotBeforeUpdate返回的,如果觸發某些回調函數時需要?到DOM元素的狀態,則將對?或計算的過程遷移?getSnapshotBeforeUpdate,然后在componentDidUpdate中統?觸發回調或更新狀態。

卸載階段:

-componentWillUnmount:當我們的組件被卸載或者銷毀了就會調?,我們可以在這個函數?去清除?些定時器,取消?絡請求,清理?效的DOM元素等垃圾清理?作。

總結:

  • componentWillMount:在渲染之前執行,用于根組件中的 App 級配置;
  • componentDidMount:在第一次渲染之后執行,可以在這里做AJAX請求,DOM的操作或狀態更新以及設置事件監聽器;
  • componentWillReceiveProps:在初始化render的時候不會執行,它會在組件接受到新的狀態(Props)時被觸發,一般用于父組件狀態更新時子組件的重新渲染
  • shouldComponentUpdate:確定是否更新組件。默認情況下,它返回true。如果確定在state或props更新后組件不需要在重新渲染,則可以返回false,這是一個提高性能的方法;
  • componentWillUpdate:在shouldComponentUpdate返回true確定要更新組件之前件之前執行;
  • componentDidUpdate:它主要用于更新DOM以響應props或state更改;
  • componentWillUnmount:它用于取消任何的網絡請求,或刪除與組件關聯的所有事件監聽器。

setState之后 發生了什么?

  • (1)代碼中調用 setState 函數之后,React 會將傳入的參數對象與組件當前的狀態合并,然后觸發所謂的調和過程(Reconciliation)。
  • (2)經過調和過程,React 會以相對高效的方式根據新的狀態構建 React 元素樹并且著手重新渲染整個 UI 界面;
  • (3)在 React 得到元素樹之后,React 會自動計算出新的樹與老樹的節點差異,然后根據差異對界面進行最小化重渲染;
  • (4)在差異計算算法中,React 能夠相對精確地知道哪些位置發生了改變以及應該如何改變,這就保證了按需更新,而不是全部重新渲染。

setState的調用會引起React的更新生命周期的4個函數執行。

shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate

react 實現一個全局的 dialog

import React, { Component } from 'react';
import { is, fromJS } from 'immutable';
import ReactDOM from 'react-dom';
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
import './dialog.css';
let defaultState = {
  alertStatus:false,
  alertTip:"提示",
  closeDialog:function(){},
  childs:''
}
class Dialog extends Component{
  state = {
    ...defaultState
  };
  // css動畫組件設置為目標組件
  FirstChild = props => {
    const childrenArray = React.Children.toArray(props.children);
    return childrenArray[0] || null;
  }
  //打開彈窗
  open =(options)=>{
    options = options || {};
    options.alertStatus = true;
    var props = options.props || {};
    var childs = this.renderChildren(props,options.childrens) || '';
    console.log(childs);
    this.setState({
      ...defaultState,
      ...options,
      childs
    })
  }
  //關閉彈窗
  close(){
    this.state.closeDialog();
    this.setState({
      ...defaultState
    })
  }
  renderChildren(props,childrens) {
    //遍歷所有子組件
    var childs = [];
    childrens = childrens || [];
    var ps = {
        ...props,  //給子組件綁定props
        _close:this.close  //給子組件也綁定一個關閉彈窗的事件    
       };
    childrens.forEach((currentItem,index) => {
        childs.push(React.createElement(
            currentItem,
            {
                ...ps,
                key:index
            }
        ));
    })
    return childs;
  }
  shouldComponentUpdate(nextProps, nextState){
    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
  }
   
  render(){
    return (
      <ReactCSSTransitionGroup
        component={this.FirstChild}
        transitionName='hide'
        transitionEnterTimeout={300}
        transitionLeaveTimeout={300}>
        <div className="dialog-con" style={this.state.alertStatus? {display:'block'}:{display:'none'}}>
            {this.state.childs}        </div>
      </ReactCSSTransitionGroup>
    );
  }
}
let div = document.createElement('div');
let props = {
   
};
document.body.appendChild(div);
let Box = ReactD

子類:

//子類jsx
import React, { Component } from 'react';
class Child extends Component {
    constructor(props){
        super(props);
        this.state = {date: new Date()};
  }
  showValue=()=>{
    this.props.showValue && this.props.showValue()
  }
  render() {
    return (
      <div className="Child">
        <div className="content">
           Child           <button onClick={this.showValue}>調用父的方法</button>
        </div>
      </div>
    );
  }
}
export default Child;

css:

.dialog-con{
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.3);
}

React的嚴格模式如何使用,有什么用處?

StrictMode 是一個用來突出顯示應用程序中潛在問題的工具。與 Fragment 一樣,StrictMode 不會渲染任何可見的 UI。它為其后代元素觸發額外的檢查和警告。
可以為應用程序的任何部分啟用嚴格模式。例如:

import React from 'react';
function ExampleApplication() {
  return (
    <div>
      <Header />
      <React.StrictMode>        
        <div>
          <ComponentOne />
          <ComponentTwo />
        </div>
      </React.StrictMode>      
      <Footer />
    </div>
  );
}


在上述的示例中,不會對 HeaderFooter 組件運行嚴格模式檢查。但是,ComponentOneComponentTwo 以及它們的所有后代元素都將進行檢查。

StrictMode 目前有助于:

  • 識別不安全的生命周期
  • 關于使用過時字符串 ref API 的警告
  • 關于使用廢棄的 findDOMNode 方法的警告
  • 檢測意外的副作用
  • 檢測過時的 context API

class類的key改了,會發生什么,會執行哪些周期函數?

在開發過程中,我們需要保證某個元素的 key 在其同級元素中具有唯一性。在 React Diff 算法中 React 會借助元素的 Key 值來判斷該元素是新近創建的還是被移動而來的元素,從而減少不必要的元素重渲染。此外,React 還需要借助 Key 值來判斷元素與本地狀態的關聯關系,因此我們絕不可忽視轉換函數中 Key 的重要性。

答:componentWillMount componentDidMount render

React.forwardRef有什么用

forwardRef

  • 使用forwardRefforward在這里是「傳遞」的意思)后,就能跨組件傳遞ref
  • 在例子中,我們將inputRefForm跨組件傳遞到MyInput中,并與input產生關聯
const MyInput = forwardRef((props, ref) => {
  return <input {...props} ref={ref} />;
});

function Form() {
  const inputRef = useRef(null);

  function handleClick() {
    inputRef.current.focus();
  }

  return (
    <>
      <MyInput ref={inputRef} />
      <button onClick={handleClick}>
        Focus the input
      </button>
    </>
  );
}

useImperativeHandle

除了「限制跨組件傳遞ref」外,還有一種「防止ref失控的措施」,那就是useImperativeHandle,他的邏輯是這樣的:既然「ref失控」是由于「使用了不該被使用的DOM方法」(比如appendChild),那我可以限制「ref中只存在可以被使用的方法」。用useImperativeHandle修改我們的MyInput組件:

const MyInput = forwardRef((props, ref) => {
  const realInputRef = useRef(null);
  useImperativeHandle(ref, () => ({
    focus() {
      realInputRef.current.focus();
    },
  }));
  return <input {...props} ref={realInputRef} />;
});

現在,Form組件中通過inputRef.current只能取到如下數據結構:

{
  focus() {
    realInputRef.current.focus();
  },
}

就杜絕了「開發者通過ref取到DOM后,執行不該被使用的API,出現ref失控」的情況

  • 為了防止錯用/濫用導致ref失控,React限制「默認情況下,不能跨組件傳遞ref」
  • 為了破除這種限制,可以使用forwardRef。
  • 為了減少refDOM的濫用,可以使用useImperativeHandle限制ref傳遞的數據結構。

原文鏈接:https://blog.csdn.net/beifeng11996/article/details/127033765

欄目分類
最近更新