React性能debug場景解決記錄
前言
之前開發(fā)重構(gòu)項目的時候,遇到了一些問題, 如 hooks
的性能問題和 quill
的重載問題。本文就是記錄這些問題的解決過程。
場景
在基于富文本的輸入場景中,我們發(fā)現(xiàn)在輸入回車后會出現(xiàn)明顯的卡頓現(xiàn)象。為了更好地展示此類場景,這里使用了一個簡單的例子展示。
function App() { const [value, setValue] = useState(''); // mock 調(diào)用多次 hooks const hook1 = useHooks(); //... const hook20 = useHooks(); const modules = useMemo(() => ({ toolbar: { container: '#toolbar', handlers: { }, }, }), []); return (<div className={'container'}> <CustomToolbar/> <ReactQuill ref={editorRef} theme="snow" value={value} modules={modules} onChange={setValue}/> <form className="todo-list"> {/* ... */} </form> </div>) }
這是頁面的主要結(jié)構(gòu), 內(nèi)容分別是一堆 hooks
+ quill
+ 其他操作(這里用一個 TODO list
來替代)
性能監(jiān)控
既然是卡頓,那當然屬于性能方面的問題 ,這里就輪到 Chrome 的性能監(jiān)控出場了: 重復步驟, 最后縮短監(jiān)控范圍, 點擊卡頓的任務
再來看下調(diào)用樹:
很明顯, 光看這里很難發(fā)現(xiàn)是頁面那個地方的問題, 都是 react
的源碼執(zhí)行函數(shù)
最關鍵的點在于自上而下
那一欄:
從這里, 我們很明顯的就能看到是這個 hooks - useI18n
影響到了
因為這是一個多語言 hooks, 所以它的引用范圍特別廣
因為不方便透露源碼, 大概的邏輯是這樣的:
const useHooks = () => { const {lang, handle:langHandle} = useContext(myContext); const handle = (number) => { langHandle(); } return { value: lang, setValue: handle } }
解決方案
這里我嘗試加上 react 的性能優(yōu)化 useMemo
:
const useHooks = () => { const {lang, handle:langHandle} = useContext(myContext); const handle = (number) => { langHandle(); } return useMemo(() => ({ value: lang, setValue: handle }), [lang, handle]) }
再通使用 Chrome
的性能監(jiān)控, 發(fā)現(xiàn)問題已經(jīng)緩解
由此可得出結(jié)論, 在多場景使用的 hooks
中, 可通過在返回值中加上 useMemo
來提高性能
當然, 除了 hooks
的優(yōu)化, 阻止其他組件的重渲染, 也可以緩解一定的渲染性能問題
這里又回到了我們老生常談的 react
性能優(yōu)化那一套, 就不贅述了
quill.js 的重渲染
在 function
組件中添加 quill.js
富文本的時候, 會經(jīng)常出現(xiàn)重復渲染導致編輯器加載出現(xiàn)問題的場景, 報錯如圖:
一般來說都是因為 quill
的 modules
對象指向改變了, 這一點在 hooks
組件中會經(jīng)常遇到:
function App(){ const modules = { toolbar: { container: '#toolbar', handlers: { handleClick }, }, } return ( <ReactQuill ref={editorRef} theme="snow" value={value} modules={modules} onChange={setValue}/> ) }
如上述的代碼, 由于 react
的機制問題, 在每次 render
時, 都會觸發(fā) reRender
, 重新聲明一個 modules
, 造成 react-quill
中的傳值問題
常見的解決方案就是萬能的 useRef
了:
function App(){ const modulesRef = useRef({ toolbar: { container: '#toolbar', handlers: { handleClick }, }, }) return ( <ReactQuill ref={editorRef} theme="snow" value={value} modules={modulesRef.current} onChange={setValue}/> ) }
在 react
的 hooks
中, useRef
反而是一個比較 OOP
的函數(shù), 因為設置之后, 不管 render
幾次, 他的對象引用都不會變化;
就像是 class
中構(gòu)造函數(shù)里設置了 this.query = {}
, 在 render
過程中 query
值引用都是不變的
由此, 很多自定義 hooks
, 都用上了他
比如最常見的 useUpdateEffect
:
const createUpdateEffect = (hook) => (effect, deps) => { const isMounted = useRef(false); // for react-refresh hook(() => { return () => { isMounted.current = false; }; }, []); hook(() => { if (!isMounted.current) { isMounted.current = true; } else { return effect(); } }, deps); }; useUpdateEffect = createUpdateEffect(useEffect)
代碼來源于 ahooks, 使用 ref
的值來標記一個私有化值
原理都是很簡單的,但是在開發(fā)中想要得心應手,還需要更多的練習。
總結(jié)
使用 hooks
進行組件開發(fā)時,頻繁更新會影響性能。
通過優(yōu)化代碼避免無用渲染,提高組件性能。
在使用 quill
編輯器時,重載頁面或組件會導致編輯內(nèi)容丟失。
通過 useRef
的使用可以保證對象指向從而解決該問題,保證編輯器穩(wěn)定可靠。
在開發(fā)中遇到問題是常見的,需要及時記錄和解決,提高開發(fā)效率和質(zhì)量。
以上就是React性能debug場景解決記錄的詳細內(nèi)容,更多關于React性能debug的資料請關注腳本之家其它相關文章!
相關文章
react-native?父函數(shù)組件調(diào)用類子組件的方法(實例詳解)
這篇文章主要介紹了react-native?父函數(shù)組件調(diào)用類子組件的方法,通過詳細步驟介紹了React 函數(shù)式組件之父組件調(diào)用子組件的方法,代碼簡單易懂,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-09-09圖文示例講解useState與useReducer性能區(qū)別
這篇文章主要為大家介紹了useState與useReducer性能區(qū)別圖文示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-05-05React Native中ScrollView組件輪播圖與ListView渲染列表組件用法實例分析
這篇文章主要介紹了React Native中ScrollView組件輪播圖與ListView渲染列表組件用法,結(jié)合實例形式詳細分析了ScrollView組件輪播圖與ListView渲染列表組件具體功能、使用方法與操作注意事項,需要的朋友可以參考下2020-01-01React父組件數(shù)據(jù)實時更新了,子組件沒有更新的問題
這篇文章主要介紹了React父組件數(shù)據(jù)實時更新了,子組件沒有更新的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-03-03React使用useImperativeHandle自定義暴露給父組件的示例詳解
useImperativeHandle?是?React?提供的一個自定義?Hook,用于在函數(shù)組件中顯式地暴露給父組件特定實例的方法,本文將介紹?useImperativeHandle的基本用法、常見應用場景,需要的可以參考下2024-03-03