1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        高頻react面試題20道(附詳解)

        共 24621字,需瀏覽 50分鐘

         ·

        2021-09-23 04:02

         大廠技術(shù)  高級(jí)前端  Node進(jìn)階

        點(diǎn)擊上方 程序員成長(zhǎng)指北,關(guān)注公眾號(hào)

        回復(fù)1,加入高級(jí)Node交流群

        作者:前端要努力

        原文:https://github.com/whylisa/front-end-interview


        上次分享了一篇vue面試題大全,有小伙伴私聊需要 react 的,這篇是react相關(guān)不錯(cuò)的面試題講解,學(xué)習(xí)下!

        1. React 事件機(jī)制

        <div onClick={this.handleClick.bind(this)}>點(diǎn)我</div>

        React并不是將click事件綁定到了div的真實(shí)DOM上,而是在document處監(jiān)聽了所有的事件,當(dāng)事件發(fā)生并且冒泡到document處的時(shí)候,React將事件內(nèi)容封裝并交由真正的處理函數(shù)運(yùn)行。這樣的方式不僅僅減少了內(nèi)存的消耗,還能在組件掛在銷毀時(shí)統(tǒng)一訂閱和移除事件。

        除此之外,冒泡到document上的事件也不是原生的瀏覽器事件,而是由react自己實(shí)現(xiàn)的合成事件(SyntheticEvent)。因此如果不想要是事件冒泡的話應(yīng)該調(diào)用event.preventDefault()方法,而不是調(diào)用event.stopProppagation()方法。

        77fa6b2a59c92e160bc171f9c80783e7.jpg

        JSX 上寫的事件并沒有綁定在對(duì)應(yīng)的真實(shí) DOM 上,而是通過事件代理的方式,將所有的事件都統(tǒng)一綁定在了 document 上。這樣的方式不僅減少了內(nèi)存消耗,還能在組件掛載銷毀時(shí)統(tǒng)一訂閱和移除事件。

        另外冒泡到 document 上的事件也不是原生瀏覽器事件,而是 React 自己實(shí)現(xiàn)的合成事件(SyntheticEvent)。因此我們?nèi)绻幌胍录芭莸脑?,調(diào)用 event.stopPropagation 是無效的,而應(yīng)該調(diào)用 event.preventDefault。

        實(shí)現(xiàn)合成事件的目的如下:

        • 合成事件首先抹平了瀏覽器之間的兼容問題,另外這是一個(gè)跨瀏覽器原生事件包裝器,賦予了跨瀏覽器開發(fā)的能力;
        • 對(duì)于原生瀏覽器事件來說,瀏覽器會(huì)給監(jiān)聽器創(chuàng)建一個(gè)事件對(duì)象。如果你有很多的事件監(jiān)聽,那么就需要分配很多的事件對(duì)象,造成高額的內(nèi)存分配問題。但是對(duì)于合成事件來說,有一個(gè)事件池專門來管理它們的創(chuàng)建和銷毀,當(dāng)事件需要被使用時(shí),就會(huì)從池子中復(fù)用對(duì)象,事件回調(diào)結(jié)束后,就會(huì)銷毀事件對(duì)象上的屬性,從而便于下次復(fù)用事件對(duì)象。

        2. React的事件和普通的HTML事件有什么不同?

        區(qū)別:

        • 對(duì)于事件名稱命名方式,原生事件為全小寫,react 事件采用小駝峰;
        • 對(duì)于事件函數(shù)處理語法,原生事件為字符串,react 事件為函數(shù);
        • react 事件不能采用 return false 的方式來阻止瀏覽器的默認(rèn)行為,而必須要地明確地調(diào)用preventDefault()來阻止默認(rèn)行為。

        合成事件是 react 模擬原生 DOM 事件所有能力的一個(gè)事件對(duì)象,其優(yōu)點(diǎn)如下:

        • 兼容所有瀏覽器,更好的跨平臺(tái);
        • 將事件統(tǒng)一存放在一個(gè)數(shù)組,避免頻繁的新增與刪除(垃圾回收)。
        • 方便 react 統(tǒng)一管理和事務(wù)機(jī)制。

        事件的執(zhí)行順序?yàn)樵录葓?zhí)行,合成事件后執(zhí)行,合成事件會(huì)冒泡綁定到 document 上,所以盡量避免原生事件與合成事件混用,如果原生事件阻止冒泡,可能會(huì)導(dǎo)致合成事件不執(zhí)行,因?yàn)樾枰芭莸絛ocument 上合成事件才會(huì)執(zhí)行。

        3. React 組件中怎么做事件代理?它的原理是什么?

        React基于Virtual DOM實(shí)現(xiàn)了一個(gè)SyntheticEvent層(合成事件層),定義的事件處理器會(huì)接收到一個(gè)合成事件對(duì)象的實(shí)例,它符合W3C標(biāo)準(zhǔn),且與原生的瀏覽器事件擁有同樣的接口,支持冒泡機(jī)制,所有的事件都自動(dòng)綁定在最外層上。

        在React底層,主要對(duì)合成事件做了兩件事:

        • **事件委派:**React會(huì)把所有的事件綁定到結(jié)構(gòu)的最外層,使用統(tǒng)一的事件監(jiān)聽器,這個(gè)事件監(jiān)聽器上維持了一個(gè)映射來保存所有組件內(nèi)部事件監(jiān)聽和處理函數(shù)。
        • **自動(dòng)綁定:**React組件中,每個(gè)方法的上下文都會(huì)指向該組件的實(shí)例,即自動(dòng)綁定this為當(dāng)前組件。

        4. React 高階組件、Render props、hooks 有什么區(qū)別,為什么要不斷迭代

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

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

        (1)HOC

        官方解釋∶

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

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

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

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

        HOC的優(yōu)缺點(diǎn)∶

        • 優(yōu)點(diǎn)∶ 邏輯服用、不影響被包裹組件的內(nèi)部邏輯。
        • 缺點(diǎn)∶ hoc傳遞給被包裹組件的props容易和被包裹后的組件重名,進(jìn)而被覆蓋

        **(2)**Render props

        官方解釋∶

        "render prop"是指一種在 React 組件之間使用一個(gè)值為函數(shù)的 prop 共享代碼的簡(jiǎn)單技術(shù)

        具有render prop 的組件接受一個(gè)返回React元素的函數(shù),將render的渲染邏輯注入到組件內(nèi)部。在這里,"render"的命名可以是任何其他有效的標(biāo)識(shí)符。

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

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

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

        由此可以看到,render props的優(yōu)缺點(diǎn)也很明顯∶

        • 優(yōu)點(diǎn):數(shù)據(jù)共享、代碼復(fù)用,將組件內(nèi)的state作為props傳遞給調(diào)用者,將渲染邏輯交給調(diào)用者。
        • 缺點(diǎn):無法在 return 語句外訪問數(shù)據(jù)、嵌套寫法不夠優(yōu)雅

        **(3)**Hooks

        官方解釋∶

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

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

        以上可以看出,hook解決了hoc的prop覆蓋的問題,同時(shí)使用的方式解決了render props的嵌套地獄的問題。hook的優(yōu)點(diǎn)如下∶

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

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

        總結(jié)∶

        Hoc、render props和hook都是為了解決代碼復(fù)用的問題,但是hoc和render props都有特定的使用場(chǎng)景和明顯的缺點(diǎn)。hook是react16.8更新的新的API,讓組件邏輯復(fù)用更簡(jiǎn)潔明了,同時(shí)也解決了hoc和render props的一些缺點(diǎn)。

        5. 對(duì)React-Fiber的理解,它解決了什么問題?

        React V15 在渲染時(shí),會(huì)遞歸比對(duì) VirtualDOM 樹,找出需要變動(dòng)的節(jié)點(diǎn),然后同步更新它們, 一氣呵成。這個(gè)過程期間, React 會(huì)占據(jù)瀏覽器資源,這會(huì)導(dǎo)致用戶觸發(fā)的事件得不到響應(yīng),并且會(huì)導(dǎo)致掉幀,導(dǎo)致用戶感覺到卡頓。

        為了給用戶制造一種應(yīng)用很快的“假象”,不能讓一個(gè)任務(wù)長(zhǎng)期霸占著資源。可以將瀏覽器的渲染、布局、繪制、資源加載(例如 HTML 解析)、事件響應(yīng)、腳本執(zhí)行視作操作系統(tǒng)的“進(jìn)程”,需要通過某些調(diào)度策略合理地分配 CPU 資源,從而提高瀏覽器的用戶響應(yīng)速率, 同時(shí)兼顧任務(wù)執(zhí)行效率。

        所以 React 通過Fiber 架構(gòu),讓這個(gè)執(zhí)行過程變成可被中斷?!斑m時(shí)”地讓出 CPU 執(zhí)行權(quán),除了可以讓瀏覽器及時(shí)地響應(yīng)用戶的交互,還有其他好處:

        • 分批延時(shí)對(duì)DOM進(jìn)行操作,避免一次性操作大量 DOM 節(jié)點(diǎn),可以得到更好的用戶體驗(yàn);
        • 給瀏覽器一點(diǎn)喘息的機(jī)會(huì),它會(huì)對(duì)代碼進(jìn)行編譯優(yōu)化(JIT)及進(jìn)行熱代碼優(yōu)化,或者對(duì) reflow 進(jìn)行修正。

        **核心思想:**Fiber 也稱協(xié)程或者纖程。它和線程并不一樣,協(xié)程本身是沒有并發(fā)或者并行能力的(需要配合線程),它只是一種控制流程的讓出機(jī)制。讓出 CPU 的執(zhí)行權(quán),讓 CPU 能在這段時(shí)間執(zhí)行其他的操作。渲染的過程可以被中斷,可以將控制權(quán)交回瀏覽器,讓位給高優(yōu)先級(jí)的任務(wù),瀏覽器空閑后再恢復(fù)渲染。

        6. React.Component 和 React.PureComponent 的區(qū)別

        PureComponent表示一個(gè)純組件,可以用來優(yōu)化React程序,減少render函數(shù)執(zhí)行的次數(shù),從而提高組件的性能。

        在React中,當(dāng)prop或者state發(fā)生變化時(shí),可以通過在shouldComponentUpdate生命周期函數(shù)中執(zhí)行return false來阻止頁面的更新,從而減少不必要的render執(zhí)行。React.PureComponent會(huì)自動(dòng)執(zhí)行 shouldComponentUpdate。

        不過,pureComponent中的 shouldComponentUpdate() 進(jìn)行的是淺比較,也就是說如果是引用數(shù)據(jù)類型的數(shù)據(jù),只會(huì)比較不是同一個(gè)地址,而不會(huì)比較這個(gè)地址里面的數(shù)據(jù)是否一致。淺比較會(huì)忽略屬性和或狀態(tài)突變情況,其實(shí)也就是數(shù)據(jù)引用指針沒有變化,而數(shù)據(jù)發(fā)生改變的時(shí)候render是不會(huì)執(zhí)行的。如果需要重新渲染那么就需要重新開辟空間引用數(shù)據(jù)。PureComponent一般會(huì)用在一些純展示組件上。

        使用pureComponent的好處:當(dāng)組件更新時(shí),如果組件的props或者state都沒有改變,render函數(shù)就不會(huì)觸發(fā)。省去虛擬DOM的生成和對(duì)比過程,達(dá)到提升性能的目的。這是因?yàn)閞eact自動(dòng)做了一層淺比較。

        7. Component, Element, Instance 之間有什么區(qū)別和聯(lián)系?

        • **元素:**一個(gè)元素element是一個(gè)普通對(duì)象(plain object),描述了對(duì)于一個(gè)DOM節(jié)點(diǎn)或者其他組件component,你想讓它在屏幕上呈現(xiàn)成什么樣子。元素element可以在它的屬性props中包含其他元素(譯注:用于形成元素樹)。創(chuàng)建一個(gè)React元素element成本很低。元素element創(chuàng)建之后是不可變的。
        • **組件:**一個(gè)組件component可以通過多種方式聲明。可以是帶有一個(gè)render()方法的類,簡(jiǎn)單點(diǎn)也可以定義為一個(gè)函數(shù)。這兩種情況下,它都把屬性props作為輸入,把返回的一棵元素樹作為輸出。
        • **實(shí)例:**一個(gè)實(shí)例instance是你在所寫的組件類component class中使用關(guān)鍵字this所指向的東西(譯注:組件實(shí)例)。它用來存儲(chǔ)本地狀態(tài)和響應(yīng)生命周期事件很有用。

        函數(shù)式組件(Functional component)根本沒有實(shí)例instance。類組件(Class component)有實(shí)例instance,但是永遠(yuǎn)也不需要直接創(chuàng)建一個(gè)組件的實(shí)例,因?yàn)镽eact幫我們做了這些。

        8. React.createClass和extends Component的區(qū)別有哪些?

        React.createClass和extends Component的bai區(qū)別主要在于:

        (1)語法區(qū)別

        • createClass本質(zhì)上是一個(gè)工廠函數(shù),extends的方式更加接近最新的ES6規(guī)范的class寫法。兩種方式在語法上的差別主要體現(xiàn)在方法的定義和靜態(tài)屬性的聲明上。
        • createClass方式的方法定義使用逗號(hào),隔開,因?yàn)閏reatClass本質(zhì)上是一個(gè)函數(shù),傳遞給它的是一個(gè)Object;而class的方式定義方法時(shí)務(wù)必謹(jǐn)記不要使用逗號(hào)隔開,這是ES6 class的語法規(guī)范。

        (2)propType 和 getDefaultProps

        • React.createClass:通過proTypes對(duì)象和getDefaultProps()方法來設(shè)置和獲取props.
        • React.Component:通過設(shè)置兩個(gè)屬性propTypes和defaultProps

        (3)狀態(tài)的區(qū)別

        • React.createClass:通過getInitialState()方法返回一個(gè)包含初始值的對(duì)象
        • React.Component:通過constructor設(shè)置初始狀態(tài)

        (4)this區(qū)別

        • React.createClass:會(huì)正確綁定this
        • React.Component:由于使用了 ES6,這里會(huì)有些微不同,屬性并不會(huì)自動(dòng)綁定到 React 類的實(shí)例上。

        (5)Mixins

        • React.createClass:使用 React.createClass 的話,可以在創(chuàng)建組件時(shí)添加一個(gè)叫做 mixins 的屬性,并將可供混合的類的集合以數(shù)組的形式賦給 mixins。
        • 如果使用 ES6 的方式來創(chuàng)建組件,那么 React mixins 的特性將不能被使用了。

        9. React 高階組件是什么,和普通組件有什么區(qū)別,適用什么場(chǎng)景

        官方解釋∶

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

        高階組件(HOC)就是一個(gè)函數(shù),且該函數(shù)接受一個(gè)組件作為參數(shù),并返回一個(gè)新的組件,它只是一種組件的設(shè)計(jì)模式,這種設(shè)計(jì)模式是由react自身的組合性質(zhì)必然產(chǎn)生的。我們將它們稱為純組件,因?yàn)樗鼈兛梢越邮苋魏蝿?dòng)態(tài)提供的子組件,但它們不會(huì)修改或復(fù)制其輸入組件中的任何行為。

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

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

        1)HOC的優(yōu)缺點(diǎn)

        • 優(yōu)點(diǎn)∶ 邏輯服用、不影響被包裹組件的內(nèi)部邏輯。
        • 缺點(diǎn)∶hoc傳遞給被包裹組件的props容易和被包裹后的組件重名,進(jìn)而被覆蓋

        2)適用場(chǎng)景

        • 代碼復(fù)用,邏輯抽象
        • 渲染劫持
        • State 抽象和更改
        • Props 更改

        3)具體應(yīng)用例子

        • **權(quán)限控制:**利用高階組件的 條件渲染 特性可以對(duì)頁面進(jìn)行權(quán)限控制,權(quán)限控制一般分為兩個(gè)維度:頁面級(jí)別和 頁面元素級(jí)別
        // HOC.js
        function withAdminAuth(WrappedComponent) {
            return class extends React.Component {
                state = {
                    isAdmin: false,
                }
                async UNSAFE_componentWillMount() {
                    const currentRole = await getCurrentUserRole();
                    this.setState({
                        isAdmin: currentRole === 'Admin',
                    });
                }
                render() {
                    if (this.state.isAdmin) {
                        return <WrappedComponent {...this.props} />;
                    } else {
                        return (<div>您沒有權(quán)限查看該頁面,請(qǐng)聯(lián)系管理員!</div>);
                    }
                }
            };
        }

        // pages/page-a.js
        class PageA extends React.Component {
            constructor(props) {
                super(props);
                // something here...
            }
            UNSAFE_componentWillMount() {
                // fetching data
            }
            render() {
                // render page with data
            }
        }
        export default withAdminAuth(PageA);


        // pages/page-b.js
        class PageB extends React.Component {
            constructor(props) {
                super(props);
            // something here...
                }
            UNSAFE_componentWillMount() {
            // fetching data
            }
            render() {
            // render page with data
            }
        }
        export default withAdminAuth(PageB);
        • **組件渲染性能追蹤:**借助父組件子組件生命周期規(guī)則捕獲子組件的生命周期,可以方便的對(duì)某個(gè)組件的渲染時(shí)間進(jìn)行記錄∶
        class Home extends React.Component {
                render() {
                    return (<h1>Hello World.</h1>);
                }
            }
            function withTiming(WrappedComponent) {
                return class extends WrappedComponent {
                    constructor(props) {
                        super(props);
                        this.start = 0;
                        this.end = 0;
                    }
                    UNSAFE_componentWillMount() {
                        super.componentWillMount && super.componentWillMount();
                        this.start = Date.now();
                    }
                    componentDidMount() {
                        super.componentDidMount && super.componentDidMount();
                        this.end = Date.now();
                        console.log(`${WrappedComponent.name} 組件渲染時(shí)間為 ${this.end - this.start} ms`);
                    }
                    render() {
                        return super.render();
                    }
                };
            }

            export default withTiming(Home);   

        注意:withTiming 是利用 反向繼承 實(shí)現(xiàn)的一個(gè)高階組件,功能是計(jì)算被包裹組件(這里是 Home 組件)的渲染時(shí)間。

        • 頁面復(fù)用
        const withFetching = fetching => WrappedComponent => {
            return class extends React.Component {
                state = {
                    data: [],
                }
                async UNSAFE_componentWillMount() {
                    const data = await fetching();
                    this.setState({
                        data,
                    });
                }
                render() {
                    return <WrappedComponent data={this.state.data} {...this.props} />;
                }
            }
        }

        // pages/page-a.js
        export default withFetching(fetching('science-fiction'))(MovieList);
        // pages/page-b.js
        export default withFetching(fetching('action'))(MovieList);
        // pages/page-other.js
        export default withFetching(fetching('some-other-type'))(MovieList);

        10. 對(duì)componentWillReceiveProps 的理解

        該方法當(dāng)props發(fā)生變化時(shí)執(zhí)行,初始化render時(shí)不執(zhí)行,在這個(gè)回調(diào)函數(shù)里面,你可以根據(jù)屬性的變化,通過調(diào)用this.setState()來更新你的組件狀態(tài),舊的屬性還是可以通過this.props來獲取,這里調(diào)用更新狀態(tài)是安全的,并不會(huì)觸發(fā)額外的render調(diào)用。

        **使用好處:**在這個(gè)生命周期中,可以在子組件的render函數(shù)執(zhí)行前獲取新的props,從而更新子組件自己的state。可以將數(shù)據(jù)請(qǐng)求放在這里進(jìn)行執(zhí)行,需要傳的參數(shù)則從componentWillReceiveProps(nextProps)中獲取。而不必將所有的請(qǐng)求都放在父組件中。于是該請(qǐng)求只會(huì)在該組件渲染時(shí)才會(huì)發(fā)出,從而減輕請(qǐng)求負(fù)擔(dān)。componentWillReceiveProps在初始化render的時(shí)候不會(huì)執(zhí)行,它會(huì)在Component接受到新的狀態(tài)(Props)時(shí)被觸發(fā),一般用于父組件狀態(tài)更新時(shí)子組件的重新渲染。

        11. 哪些方法會(huì)觸發(fā) React 重新渲染?重新渲染 render 會(huì)做些什么?

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

        • setState()方法被調(diào)用

        setState 是 React 中最常用的命令,通常情況下,執(zhí)行 setState 會(huì)觸發(fā) render。但是這里有個(gè)點(diǎn)值得關(guān)注,執(zhí)行 setState 的時(shí)候不一定會(huì)重新渲染。當(dāng) setState 傳入 null 時(shí),并不會(huì)觸發(fā) 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 未發(fā)生變化,那么子組件也會(huì)重新渲染,進(jìn)而觸發(fā) render

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

        • 會(huì)對(duì)新舊 VNode 進(jìn)行對(duì)比,也就是我們所說的Diff算法。
        • 對(duì)新舊兩棵樹進(jìn)行一個(gè)深度優(yōu)先遍歷,這樣每一個(gè)節(jié)點(diǎn)都會(huì)一個(gè)標(biāo)記,在到深度遍歷的時(shí)候,每遍歷到一和個(gè)節(jié)點(diǎn),就把該節(jié)點(diǎn)和新的節(jié)點(diǎn)樹進(jìn)行對(duì)比,如果有差異就放到一個(gè)對(duì)象里面
        • 遍歷差異對(duì)象,根據(jù)差異的類型,根據(jù)對(duì)應(yīng)對(duì)規(guī)則更新VNode

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

        12. React如何判斷什么時(shí)候重新渲染組件?

        組件狀態(tài)的改變可以因?yàn)?code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;outline: 0px;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.047);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">props的改變,或者直接通過setState方法改變。組件獲得新的狀態(tài),然后React決定是否應(yīng)該重新渲染組件。只要組件的state發(fā)生變化,React就會(huì)對(duì)組件進(jìn)行重新渲染。這是因?yàn)镽eact中的shouldComponentUpdate方法默認(rèn)返回true,這就是導(dǎo)致每次更新都重新渲染的原因。

        當(dāng)React將要渲染組件時(shí)會(huì)執(zhí)行shouldComponentUpdate方法來看它是否返回true(組件應(yīng)該更新,也就是重新渲染)。所以需要重寫shouldComponentUpdate方法讓它根據(jù)情況返回true或者false來告訴React什么時(shí)候重新渲染什么時(shí)候跳過重新渲染。

        13. React聲明組件有哪幾種方法,有什么不同?

        React 聲明組件的三種方式:

        • 函數(shù)式定義的無狀態(tài)組件
        • ES5原生方式React.createClass定義的組件
        • ES6形式的extends React.Component定義的組件

        (1)無狀態(tài)函數(shù)式組件

        它是為了創(chuàng)建純展示組件,這種組件只負(fù)責(zé)根據(jù)傳入的props來展示,不涉及到state狀態(tài)的操作

        組件不會(huì)被實(shí)例化,整體渲染性能得到提升,不能訪問this對(duì)象,不能訪問生命周期的方法

        (2)ES5 原生方式 React.createClass // RFC

        React.createClass會(huì)自綁定函數(shù)方法,導(dǎo)致不必要的性能開銷,增加代碼過時(shí)的可能性。

        (3)E6繼承形式 React.Component // RCC

        目前極為推薦的創(chuàng)建有狀態(tài)組件的方式,最終會(huì)取代React.createClass形式;相對(duì)于 React.createClass可以更好實(shí)現(xiàn)代碼復(fù)用。

        無狀態(tài)組件相對(duì)于于后者的區(qū)別:

        與無狀態(tài)組件相比,React.createClass和React.Component都是創(chuàng)建有狀態(tài)的組件,這些組件是要被實(shí)例化的,并且可以訪問組件的生命周期方法。

        React.createClass與React.Component區(qū)別:

        ① 函數(shù)this自綁定

        • React.createClass創(chuàng)建的組件,其每一個(gè)成員函數(shù)的this都有React自動(dòng)綁定,函數(shù)中的this會(huì)被正確設(shè)置。
        • React.Component創(chuàng)建的組件,其成員函數(shù)不會(huì)自動(dòng)綁定this,需要開發(fā)者手動(dòng)綁定,否則this不能獲取當(dāng)前組件實(shí)例對(duì)象。

        ② 組件屬性類型propTypes及其默認(rèn)props屬性defaultProps配置不同

        • React.createClass在創(chuàng)建組件時(shí),有關(guān)組件props的屬性類型及組件默認(rèn)的屬性會(huì)作為組件實(shí)例的屬性來配置,其中defaultProps是使用getDefaultProps的方法來獲取默認(rèn)組件屬性的
        • React.Component在創(chuàng)建組件時(shí)配置這兩個(gè)對(duì)應(yīng)信息時(shí),他們是作為組件類的屬性,不是組件實(shí)例的屬性,也就是所謂的類的靜態(tài)屬性來配置的。

        ③ 組件初始狀態(tài)state的配置不同

        • React.createClass創(chuàng)建的組件,其狀態(tài)state是通過getInitialState方法來配置組件相關(guān)的狀態(tài);
        • React.Component創(chuàng)建的組件,其狀態(tài)state是在constructor中像初始化組件屬性一樣聲明的。

        14. 對(duì)有狀態(tài)組件和無狀態(tài)組件的理解及使用場(chǎng)景

        (1)有狀態(tài)組件

        特點(diǎn):

        • 是類組件
        • 有繼承
        • 可以使用this
        • 可以使用react的生命周期
        • 使用較多,容易頻繁觸發(fā)生命周期鉤子函數(shù),影響性能
        • 內(nèi)部使用 state,維護(hù)自身狀態(tài)的變化,有狀態(tài)組件根據(jù)外部組件傳入的 props 和自身的 state進(jìn)行渲染。

        使用場(chǎng)景:

        • 需要使用到狀態(tài)的。
        • 需要使用狀態(tài)操作組件的(無狀態(tài)組件的也可以實(shí)現(xiàn)新版本react hooks也可實(shí)現(xiàn))

        總結(jié):

        類組件可以維護(hù)自身的狀態(tài)變量,即組件的 state ,類組件還有不同的生命周期方法,可以讓開發(fā)者能夠在組件的不同階段(掛載、更新、卸載),對(duì)組件做更多的控制。類組件則既可以充當(dāng)無狀態(tài)組件,也可以充當(dāng)有狀態(tài)組件。當(dāng)一個(gè)類組件不需要管理自身狀態(tài)時(shí),也可稱為無狀態(tài)組件。

        (2)無狀態(tài)組件

        特點(diǎn):

        • 不依賴自身的狀態(tài)state
        • 可以是類組件或者函數(shù)組件。
        • 可以完全避免使用 this 關(guān)鍵字。(由于使用的是箭頭函數(shù)事件無需綁定)
        • 有更高的性能。當(dāng)不需要使用生命周期鉤子時(shí),應(yīng)該首先使用無狀態(tài)函數(shù)組件
        • 組件內(nèi)部不維護(hù) state ,只根據(jù)外部組件傳入的 props 進(jìn)行渲染的組件,當(dāng) props 改變時(shí),組件重新渲染。

        使用場(chǎng)景:

        • 組件不需要管理 state,純展示

        優(yōu)點(diǎn):

        • 簡(jiǎn)化代碼、專注于 render
        • 組件不需要被實(shí)例化,無生命周期,提升性能。輸出(渲染)只取決于輸入(屬性),無副作用
        • 視圖和數(shù)據(jù)的解耦分離

        缺點(diǎn):

        • 無法使用 ref
        • 無生命周期方法
        • 無法控制組件的重渲染,因?yàn)闊o法使用shouldComponentUpdate 方法,當(dāng)組件接受到新的屬性時(shí)則會(huì)重渲染

        總結(jié):

        組件內(nèi)部狀態(tài)且與外部無關(guān)的組件,可以考慮用狀態(tài)組件,這樣狀態(tài)樹就不會(huì)過于復(fù)雜,易于理解和管理。當(dāng)一個(gè)組件不需要管理自身狀態(tài)時(shí),也就是無狀態(tài)組件,應(yīng)該優(yōu)先設(shè)計(jì)為函數(shù)組件。比如自定義的 <Button/>、 <Input /> 等組件。

        15. 對(duì)React中Fragment的理解,它的使用場(chǎng)景是什么?

        在React中,組件返回的元素只能有一個(gè)根元素。為了不添加多余的DOM節(jié)點(diǎn),我們可以使用Fragment標(biāo)簽來包裹所有的元素,F(xiàn)ragment標(biāo)簽不會(huì)渲染出任何元素。React官方對(duì)Fragment的解釋:

        React 中的一個(gè)常見模式是一個(gè)組件返回多個(gè)元素。Fragments 允許你將子列表分組,而無需向 DOM 添加額外節(jié)點(diǎn)。

        import React, { Component, Fragment } from 'react'

        // 一般形式
        render() {
          return (
            <React.Fragment>
              <ChildA />
              <ChildB />
              <ChildC />
            </React.Fragment>
          );
        }
        // 也可以寫成以下形式
        render() {
          return (
            <>
              <ChildA />
              <ChildB />
              <ChildC />
            </>
          );
        }

        16. React如何獲取組件對(duì)應(yīng)的DOM元素?

        可以用ref來獲取某個(gè)子節(jié)點(diǎn)的實(shí)例,然后通過當(dāng)前class組件實(shí)例的一些特定屬性來直接獲取子節(jié)點(diǎn)實(shí)例。ref有三種實(shí)現(xiàn)方法:

        • 字符串格式:字符串格式,這是React16版本之前用得最多的,例如:<p ref="info">span</p>
        • 函數(shù)格式:ref對(duì)應(yīng)一個(gè)方法,該方法有一個(gè)參數(shù),也就是對(duì)應(yīng)的節(jié)點(diǎn)實(shí)例,例如:<p ref={ele => this.info = ele}></p>
        • createRef方法:React 16提供的一個(gè)API,使用React.createRef()來實(shí)現(xiàn)

        17. React中可以在render訪問refs嗎?為什么?

        <>
          <span id="name" ref={this.spanRef}>{this.state.title}</span>
          <span>{
             this.spanRef.current ? '有值' : '無值'
          }</span>
        </>

        不可以,render 階段 DOM 還沒有生成,無法獲取 DOM。DOM 的獲取需要在 pre-commit 階段和 commit 階段:

        image.png

        18. 對(duì)React的插槽(Portals)的理解,如何使用,有哪些使用場(chǎng)景

        React 官方對(duì) Portals 的定義:

        Portal 提供了一種將子節(jié)點(diǎn)渲染到存在于父組件以外的 DOM 節(jié)點(diǎn)的優(yōu)秀的方案

        Portals 是React 16提供的官方解決方案,使得組件可以脫離父組件層級(jí)掛載在DOM樹的任何位置。通俗來講,就是我們 render 一個(gè)組件,但這個(gè)組件的 DOM 結(jié)構(gòu)并不在本組件內(nèi)。

        Portals語法如下:

        ReactDOM.createPortal(child, container);
        • 第一個(gè)參數(shù) child 是可渲染的 React 子項(xiàng),比如元素,字符串或者片段等;
        • 第二個(gè)參數(shù) container 是一個(gè) DOM 元素。

        一般情況下,組件的render函數(shù)返回的元素會(huì)被掛載在它的父級(jí)組件上:

        import DemoComponent from './DemoComponent';
        render() {
          // DemoComponent元素會(huì)被掛載在id為parent的div的元素上
          return (
            <div id="parent">
                <DemoComponent />
            </div>
          );
        }

        然而,有些元素需要被掛載在更高層級(jí)的位置。最典型的應(yīng)用場(chǎng)景:當(dāng)父組件具有overflow: hidden或者z-index的樣式設(shè)置時(shí),組件有可能被其他元素遮擋,這時(shí)就可以考慮要不要使用Portal使組件的掛載脫離父組件。例如:對(duì)話框,模態(tài)窗。

        import DemoComponent from './DemoComponent';
        render() {
          // react會(huì)將DemoComponent組件直接掛載在真實(shí)的 dom 節(jié)點(diǎn) domNode 上,生命周期還和16版本之前相同。
          return ReactDOM.createPortal(
            <DemoComponent />,
            domNode,
          );
        }

        19. 在React中如何避免不必要的render?

        React 基于虛擬 DOM 和高效 Diff 算法的完美配合,實(shí)現(xiàn)了對(duì) DOM 最小粒度的更新。大多數(shù)情況下,React 對(duì) DOM 的渲染效率足以業(yè)務(wù)日常。但在個(gè)別復(fù)雜業(yè)務(wù)場(chǎng)景下,性能問題依然會(huì)困擾我們。此時(shí)需要采取一些措施來提升運(yùn)行性能,其很重要的一個(gè)方向,就是避免不必要的渲染(Render)。這里提下優(yōu)化的點(diǎn):

        • shouldComponentUpdate 和 PureComponent

        在 React 類組件中,可以利用 shouldComponentUpdate或者 PureComponent 來減少因父組件更新而觸發(fā)子組件的 render,從而達(dá)到目的。shouldComponentUpdate 來決定是否組件是否重新渲染,如果不希望組件重新渲染,返回 false 即可。

        • 利用高階組件

        在函數(shù)組件中,并沒有 shouldComponentUpdate 這個(gè)生命周期,可以利用高階組件,封裝一個(gè)類似 PureComponet 的功能

        • 使用 React.memo

        React.memo 是 React 16.6 新的一個(gè) API,用來緩存組件的渲染,避免不必要的更新,其實(shí)也是一個(gè)高階組件,與 PureComponent 十分類似,但不同的是, React.memo只能用于函數(shù)組件。

        20. 對(duì) React-Intl 的理解,它的工作原理?

        React-intl是雅虎的語言國(guó)際化開源項(xiàng)目FormatJS的一部分,通過其提供的組件和API可以與ReactJS綁定。

        React-intl提供了兩種使用方法,一種是引用React組件,另一種是直接調(diào)取API,官方更加推薦在React項(xiàng)目中使用前者,只有在無法使用React組件的地方,才應(yīng)該調(diào)用框架提供的API。它提供了一系列的React組件,包括數(shù)字格式化、字符串格式化、日期格式化等。

        在React-intl中,可以配置不同的語言包,他的工作原理就是根據(jù)需要,在語言包之間進(jìn)行切換。

        Node 社群


        我組建了一個(gè)氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對(duì)Node.js學(xué)習(xí)感興趣的話(后續(xù)有計(jì)劃也可以),我們可以一起進(jìn)行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。


           “分享、點(diǎn)贊、在看” 支持一波??

        瀏覽 56
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            激情网无码 | 午夜国产在线视频 | 国产成人精品亚洲777人妖 | 黄色五月婷婷 | 99国产成人精品无码青春在线 | av好大在线观看网站先看字幕 | 看全色黄大色大片 | 俺来也俺来啦Awww官网 | ass女人光腚裸体pics | 国产成人无码精品久在线观看 |