您好,登錄后才能下訂單哦!
這篇“前端react面試題實例代碼分析”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“前端react面試題實例代碼分析”文章吧。
通過實現組件的getDefaultProps,對屬性設置默認值(ES5的寫法):
var ShowTitle = React.createClass({ getDefaultProps:function(){ return{ title : "React" } }, render : function(){ return <h2>{this.props.title}</h2> } });
PureComponent表示一個純組件,可以用來優化React程序,減少render函數執行的次數,從而提高組件的性能。
在React中,當prop或者state發生變化時,可以通過在shouldComponentUpdate生命周期函數中執行return false來阻止頁面的更新,從而減少不必要的render執行。React.PureComponent會自動執行 shouldComponentUpdate。
不過,pureComponent中的 shouldComponentUpdate() 進行的是淺比較,也就是說如果是引用數據類型的數據,只會比較不是同一個地址,而不會比較這個地址里面的數據是否一致。淺比較會忽略屬性和或狀態突變情況,其實也就是數據引用指針沒有變化,而數據發生改變的時候render是不會執行的。如果需要重新渲染那么就需要重新開辟空間引用數據。PureComponent一般會用在一些純展示組件上。
使用pureComponent的好處:當組件更新時,如果組件的props或者state都沒有改變,render函數就不會觸發。省去虛擬DOM的生成和對比過程,達到提升性能的目的。這是因為react自動做了一層淺比較。
<div onClick={this.handleClick.bind(this)}>點我</div>
React并不是將click事件綁定到了div的真實DOM上,而是在document處監聽了所有的事件,當事件發生并且冒泡到document處的時候,React將事件內容封裝并交由真正的處理函數運行。這樣的方式不僅僅減少了內存的消耗,還能在組件掛在銷毀時統一訂閱和移除事件。
除此之外,冒泡到document上的事件也不是原生的瀏覽器事件,而是由react自己實現的合成事件(SyntheticEvent)。因此如果不想要是事件冒泡的話應該調用event.preventDefault()方法,而不是調用event.stopProppagation()方法。 JSX 上寫的事件并沒有綁定在對應的真實 DOM 上,而是通過事件代理的方式,將所有的事件都統一綁定在了 document
上。這樣的方式不僅減少了內存消耗,還能在組件掛載銷毀時統一訂閱和移除事件。
另外冒泡到 document
上的事件也不是原生瀏覽器事件,而是 React 自己實現的合成事件(SyntheticEvent)。因此我們如果不想要事件冒泡的話,調用 event.stopPropagation
是無效的,而應該調用 event.preventDefault
。
實現合成事件的目的如下:
合成事件首先抹平了瀏覽器之間的兼容問題,另外這是一個跨瀏覽器原生事件包裝器,賦予了跨瀏覽器開發的能力;
對于原生瀏覽器事件來說,瀏覽器會給監聽器創建一個事件對象。如果你有很多的事件監聽,那么就需要分配很多的事件對象,造成高額的內存分配問題。但是對于合成事件來說,有一個事件池專門來管理它們的創建和銷毀,當事件需要被使用時,就會從池子中復用對象,事件回調結束后,就會銷毀事件對象上的屬性,從而便于下次復用事件對象。
這三者是目前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 => ( <h2>Hello {data.name}</h2> )}/>
由此可以看到,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只能在組件頂層使用,不可在分支語句中使用。、
Model
改變之后(可能是調用了setState
),觸發了virtual dom
的更新,再用diff
算法來把virtual DOM
比較real DOM
,看看是哪個dom
節點更新了,再渲染real dom
增加shouldComponentUpdate
鉤子對新舊props
進行比較,如果值相同則阻止更新,避免不必要的渲染,或者使用PureReactComponent
替代Component
,其內部已經封裝了shouldComponentUpdate
的淺比較邏輯
對于列表或其他結構相同的節點,為其中的每一項增加唯一key
屬性,以方便React
的diff
算法中對該節點的復用,減少節點的創建和刪除操作
render
函數中減少類似onClick={() => {doSomething()}}
的寫法,每次調用render函數時均會創建一個新的函數,即使內容沒有發生任何變化,也會導致節點沒必要的重渲染,建議將函數保存在組件的成員對象中,這樣只會創建一次
組件的props
如果需要經過一系列運算后才能拿到最終結果,則可以考慮使用reselect
庫對結果進行緩存,如果props值未發生變化,則結果直接從緩存中拿,避免高昂的運算代價
webpack-bundle-analyzer
分析當前頁面的依賴包,是否存在不合理性,如果存在,找到優化點并進行優化
參考 前端進階面試題詳細解答
簡單地說,在 React中元素(虛擬DOM)描述了你在屏幕上看到的DOM元素。
換個說法就是,在 React中元素是頁面中DOM元素的對象表示方式。在 React中組件是一個函數或一個類,它可以接受輸入并返回一個元素。
注意:工作中,為了提高開發效率,通常使用JSX語法表示 React元素(虛擬DOM)。在編譯的時候,把它轉化成一個 React. createElement調用方法。
高階函數:如果一個函數接受一個或多個函數作為參數或者返回一個函數就可稱之為高階函數。
高階組件:如果一個函數 接受一個或多個組件作為參數并且返回一個組件 就可稱之為 高階組件。
react 中的高階組件
React 中的高階組件主要有兩種形式:屬性代理和反向繼承。
屬性代理 Proxy
操作 props
抽離 state
通過 ref
訪問到組件實例
用其他元素包裹傳入的組件 WrappedComponent
反向繼承
會發現其屬性代理和反向繼承的實現有些類似的地方,都是返回一個繼承了某個父類的子類,只不過屬性代理中繼承的是 React.Component
,反向繼承中繼承的是傳入的組件 WrappedComponent
。
反向繼承可以用來做什么:
1.操作 state
高階組件中可以讀取、編輯和刪除WrappedComponent
組件實例中的state
。甚至可以增加更多的state
項,但是非常不建議這么做因為這可能會導致state
難以維護及管理。
function withLogging(WrappedComponent) { return class extends WrappedComponent { render() { return ( <div>; <h3>;Debugger Component Logging...<h3>; <p>;state:<p>; <pre>;{JSON.stringify(this.state, null, 4)}<pre>; <p>props:<p>; <pre>{JSON.stringify(this.props, null, 4)}<pre>; {super.render()} <div>; ); } }; }
2.渲染劫持(Render Highjacking)
條件渲染通過 props.isLoading 這個條件來判斷渲染哪個組件。
修改由 render() 輸出的 React 元素樹
目的是為了防止 XSS 攻擊。因為 Synbol 無法被序列化,所以 React 可以通過有沒有 $$typeof 屬性來斷出當前的 element 對象是從數據庫來的還是自己生成的。
如果沒有 $$typeof 這個屬性,react 會拒絕處理該元素。
在 React 的古老版本中,下面的寫法會出現 XSS 攻擊:
// 服務端允許用戶存儲 JSON let expectedTextButGotJSON = { type: 'div', props: { dangerouslySetInnerHTML: { __html: '/* 把你想的擱著 */' }, }, // ... }; let message = { text: expectedTextButGotJSON }; // React 0.13 中有風險 <p> {message.text} </p>
路由變成了組件
分散到各個頁面,不需要配置 比如<link> <route></route>
(1)編寫簡單直觀的代碼
React最大的價值不是高性能的虛擬DOM、封裝的事件機制、服務器端渲染,而是聲明式的直觀的編碼方式。react文檔第一條就是聲明式,React 使創建交互式 UI 變得輕而易舉。為應用的每一個狀態設計簡潔的視圖,當數據改變時 React 能有效地更新并正確地渲染組件。 以聲明式編寫 UI,可以讓代碼更加可靠,且方便調試。
(2)簡化可復用的組件
React框架里面使用了簡化的組件模型,但更徹底地使用了組件化的概念。React將整個UI上的每一個功能模塊定義成組件,然后將小的組件通過組合或者嵌套的方式構成更大的組件。React的組件具有如下的特性∶
可組合:簡單組件可以組合為復雜的組件
可重用:每個組件都是獨立的,可以被多個組件使用
可維護:和組件相關的邏輯和UI都封裝在了組件的內部,方便維護
可測試:因為組件的獨立性,測試組件就變得方便很多。
(3) Virtual DOM
真實頁面對應一個 DOM 樹。在傳統頁面的開發模式中,每次需要更新頁面時,都要手動操作 DOM 來進行更新。 DOM 操作非常昂貴。在前端開發中,性能消耗最大的就是 DOM 操作,而且這部分代碼會讓整體項目的代碼變得難 以維護。React 把真實 DOM 樹轉換成 JavaScript 對象樹,也就是 Virtual DOM,每次數據更新后,重新計算 Virtual DOM,并和上一次生成的 Virtual DOM 做對比,對發生變化的部分做批量更新。React 也提供了直觀的 shouldComponentUpdate 生命周期回調,來減少數據變化后不必要的 Virtual DOM 對比過程,以保證性能。
(4)函數式編程
React 把過去不斷重復構建 UI 的過程抽象成了組件,且在給定參數的情況下約定渲染對應的 UI 界面。React 能充分利用很多函數式方法去減少冗余代碼。此外,由于它本身就是簡單函數,所以易于測試。
(5)一次學習,隨處編寫
無論現在正在使用什么技術棧,都可以隨時引入 React來開發新特性,而不需要重寫現有代碼。
React 還可以使用 Node 進行服務器渲染,或使用 React Native 開發原生移動應用。因為 React 組件可以映射為對應的原生控件。在輸出的時候,是輸出 Web DOM,還是 Android 控件,還是 iOS 控件,就由平臺本身決定了。所以,react很方便和其他平臺集成
根據組件的職責通常把組件分為UI組件和容器組件。
UI 組件負責 UI 的呈現,容器組件負責管理數據和邏輯。
兩者通過React-Redux
提供connect
方法聯系起來
(1)setState() setState()用于設置狀態對象,其語法如下:
setState(object nextState[, function callback])
nextState,將要設置的新狀態,該狀態會和當前的state合并
callback,可選參數,回調函數。該函數會在setState設置成功,且組件重新渲染后調用。
合并nextState和當前state,并重新渲染組件。setState是React事件處理函數中和請求回調函數中觸發UI更新的主要方法。
(2)replaceState() replaceState()方法與setState()類似,但是方法只會保留nextState中狀態,原state不在nextState中的狀態都會被刪除。其語法如下:
replaceState(object nextState[, function callback])
nextState,將要設置的新狀態,該狀態會替換當前的state。
callback,可選參數,回調函數。該函數會在replaceState設置成功,且組件重新渲染后調用。
總結: setState 是修改其中的部分狀態,相當于 Object.assign,只是覆蓋,不會減少原來的狀態。而replaceState 是完全替換原來的狀態,相當于賦值,將原來的 state 替換為另一個對象,如果新狀態屬性減少,那么 state 中就沒有這個狀態了。
useState()
是什么?下面說明useState(0)
的用途:
const [count, setCounter] = useState(0); const [moreStuff, setMoreStuff] = useState(); const setCount = () => { setCounter(count + 1); setMoreStuff(); };
useState
是一個內置的 React Hook。useState(0)
返回一個元組,其中第一個參數count
是計數器的當前狀態,setCounter
提供更新計數器狀態的方法。
咱們可以在任何地方使用setCounter
方法更新計數狀態-在這種情況下,咱們在setCount
函數內部使用它可以做更多的事情,使用 Hooks,能夠使咱們的代碼保持更多功能,還可以避免過多使用基于類的組件。
通常我們輸出節點的時候都是map一個數組然后返回一個
ReactNode
,為了方便react
內部進行優化,我們必須給每一個reactNode
添加key
,這個key prop
在設計值處不是給開發者用的,而是給react用的,大概的作用就是給每一個reactNode
添加一個身份標識,方便react進行識別,在重渲染過程中,如果key一樣,若組件屬性有所變化,則react
只更新組件對應的屬性;沒有變化則不更新,如果key不一樣,則react先銷毀該組件,然后重新創建該組件
React為我們提供了PropTypes以供驗證使用。當我們向Props傳入的數據無效(向Props傳入的數據類型和驗證的數據類型不符)就會在控制臺發出警告信息。它可以避免隨著應用越來越復雜從而出現的問題。并且,它還可以讓程序變得更易讀。
import PropTypes from 'prop-types'; class Greeting extends React.Component { render() { return ( <h2>Hello, {this.props.name}</h2> ); } } Greeting.propTypes = { name: PropTypes.string };
當然,如果項目匯中使用了TypeScript,那么就可以不用PropTypes來校驗,而使用TypeScript定義接口來校驗props。
純函數是不依賴并且不會在其作用域之外修改變量狀態的函數。本質上,純函數始終在給定相同參數的情況下返回相同結果。
(1)有狀態組件
特點:
是類組件
有繼承
可以使用this
可以使用react的生命周期
使用較多,容易頻繁觸發生命周期鉤子函數,影響性能
內部使用 state,維護自身狀態的變化,有狀態組件根據外部組件傳入的 props 和自身的 state進行渲染。
使用場景:
需要使用到狀態的。
需要使用狀態操作組件的(無狀態組件的也可以實現新版本react hooks也可實現)
總結: 類組件可以維護自身的狀態變量,即組件的 state ,類組件還有不同的生命周期方法,可以讓開發者能夠在組件的不同階段(掛載、更新、卸載),對組件做更多的控制。類組件則既可以充當無狀態組件,也可以充當有狀態組件。當一個類組件不需要管理自身狀態時,也可稱為無狀態組件。
(2)無狀態組件 特點:
不依賴自身的狀態state
可以是類組件或者函數組件。
可以完全避免使用 this 關鍵字。(由于使用的是箭頭函數事件無需綁定)
有更高的性能。當不需要使用生命周期鉤子時,應該首先使用無狀態函數組件
組件內部不維護 state ,只根據外部組件傳入的 props 進行渲染的組件,當 props 改變時,組件重新渲染。
使用場景:
組件不需要管理 state,純展示
優點:
簡化代碼、專注于 render
組件不需要被實例化,無生命周期,提升性能。 輸出(渲染)只取決于輸入(屬性),無副作用
視圖和數據的解耦分離
缺點:
無法使用 ref
無生命周期方法
無法控制組件的重渲染,因為無法使用shouldComponentUpdate 方法,當組件接受到新的屬性時則會重渲染
總結: 組件內部狀態且與外部無關的組件,可以考慮用狀態組件,這樣狀態樹就不會過于復雜,易于理解和管理。當一個組件不需要管理自身狀態時,也就是無狀態組件,應該優先設計為函數組件。比如自定義的 <Button/>
、 <Input />
等組件。
可以用ref來獲取某個子節點的實例,然后通過當前class組件實例的一些特定屬性來直接獲取子節點實例。ref有三種實現方法:
字符串格式:字符串格式,這是React16版本之前用得最多的,例如:<p ref="info">span</p>
函數格式:ref對應一個方法,該方法有一個參數,也就是對應的節點實例,例如:<p ref={ele => this.info = ele}></p>
createRef方法:React 16提供的一個API,使用React.createRef()來實現
在以前, react 中所有的組件都會位于 #app 下,而使用 Portals 提供了一種脫離 #app 的組件
因此 Portals 適合脫離文檔流(out of flow) 的組件,特別是 position: absolute 與 position: fixed的組件。比如模態框,通知,警告,goTop 等。
以下是官方一個模態框的示例,可以在以下地址中測試效果
<html> <body> <div id="app"></div> <div id="modal"></div> <div id="gotop"></div> <div id="alert"></div> </body> </html>
const modalRoot = document.getElementById('modal'); class Modal extends React.Component { constructor(props) { super(props); this.el = document.createElement('div'); } componentDidMount() { modalRoot.appendChild(this.el); } componentWillUnmount() { modalRoot.removeChild(this.el); } render() { return ReactDOM.createPortal( this.props.children, this.el, ); } }
React Hooks當中的useEffect是如何區分生命周期鉤子的
useEffect可以看成是
componentDidMount
,componentDidUpdate
和componentWillUnmount
三者的結合。useEffect(callback, [source])接收兩個參數,調用方式如下
useEffect(() => { console.log('mounted'); return () => { console.log('willUnmount'); } }, [source]);
生命周期函數的調用主要是通過第二個參數[source]來進行控制,有如下幾種情況:
[source]
參數不傳時,則每次都會優先調用上次保存的函數中返回的那個函數,然后再調用外部那個函數;
[source]
參數傳[]時,則外部的函數只會在初始化時調用一次,返回的那個函數也只會最終在組件卸載時調用一次;
[source]
參數有值時,則只會監聽到數組中的值發生變化后才優先調用返回的那個函數,再調用外部的函數。
以上就是關于“前端react面試題實例代碼分析”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。