解析react?函數(shù)組件輸入卡頓問(wèn)題?usecallback?react.memo
現(xiàn)象
在輸入問(wèn)題時(shí),輸入框響應(yīng)巨慢。
效果圖

分析
右側(cè)控制臺(tái)顯示,子組件不停在mount unmount,子組件中使用了CKEditor組件,每次mount開支較大,導(dǎo)致輸入卡頓
代碼如下:
const qdata = (q.qdata || [
{ id: getQuestionId('OPTION') },
{ id: getQuestionId('OPTION') },
]) as SelectOption[];
const renderEdit = () => {
console.log('hh');
return (
<div
className={classnames(
styles.question_content_radio,
styles.question_content_radio_edit,
)}
>
{qdata.map((i, index) => (
<DNDCard key={i.id} id={i.id} index={index} moveCard={() => {}}>
<div className={styles.radio_item}>
<CKInlineEditor
config={{ placeholder: '選項(xiàng)' + (index + 1) }}
data={i.title}
onChange={(data) => {
}}
></CKInlineEditor>
</div>
</DNDCard>
))}
</div>
);
};qdata每次都會(huì)重新生成新的隨機(jī)id,導(dǎo)致組件不停卸載,掛載
const qdata = (q.qdata || [
{ id: getQuestionId('OPTION') },
{ id: getQuestionId('OPTION') },
]) as SelectOption[];
{qdata.map((i, index) => (
<DNDCard key={i.id} id={i.id} index={index} moveCard={() => {}}>
<div className={styles.radio_item}>
<CKInlineEditor
config={{ placeholder: '選項(xiàng)' + (index + 1) }}
data={i.title}
onChange={(data) => {
}}
></CKInlineEditor>
</div>
</DNDCard>
))}解決
方案一:
使用React.memo 包裹子組件,使其在只有關(guān)心的屬性更新時(shí)再重新渲染,類似pure component.
Recat.memo 的函數(shù)簽名
function memo<P extends object>(
Component: FunctionComponent<P>,
propsAreEqual?: (prevProps: Readonly<P>, nextProps: Readonly<P>) => boolean
): NamedExoticComponent<P>;export default memo(QuestionRadio, (prevprops, nextprops) => {
return prevprops.q.qdata === nextprops.q.qdata && prevprops.isEdit === nextprops.isEdit;
});效果圖, 子組件沒有隨之渲染

方案二:
使用useCallback包裹 指定render函數(shù),避免其在每次渲染時(shí)重復(fù)創(chuàng)建函數(shù),保存函數(shù)引用。
useCallback中引用的值是第一次創(chuàng)建時(shí)的值,采用閉包保存下來(lái),因此后面渲染用到的qdata屬性都是不變的,這樣該段代碼<DNDCard key={i.id} id={i.id} index={index} moveCard={() => {}}>中的key值就不會(huì)因?yàn)殡S意變動(dòng)而導(dǎo)致組件不停卸載,掛載。
這樣就避免了
ckeditor組件被重復(fù)卸載重新掛載。
代碼如下
const renderEdit = useCallback(() => {
console.log('hh');
return (
<div
className={classnames(
styles.question_content_radio,
styles.question_content_radio_edit,
)}
>
{qdata.map((i, index) => (
<DNDCard key={i.id} id={i.id} index={index} moveCard={() => {}}>
<div className={styles.radio_item}>
<CKInlineEditor
config={{ placeholder: '選項(xiàng)' + (index + 1) }}
data={i.title}
onChange={(data) => {
}}
></CKInlineEditor>
</div>
</DNDCard>
))}
</div>
);
}, []);效果圖,子組件還是渲染了,但是避免了 CKInlineEditor的開支

弊端
使用usecallback包裹renderEdit后,該函數(shù)中的所有變量都會(huì)采用第一次創(chuàng)建該函數(shù)時(shí)的值,不會(huì)隨之更新。導(dǎo)致界面無(wú)法正確顯示數(shù)據(jù)。
此處功能正常是因?yàn)?code>qdata是一個(gè)對(duì)象數(shù)組,引用地址沒變,但其值發(fā)生了變化,所以界面顯示正常。
如果是值類型,就有問(wèn)題了
我們不能依賴該性質(zhì)來(lái)投機(jī)取巧,而應(yīng)該明確的指定useCallback的依賴項(xiàng)。
最終的辦法是將生成隨機(jī)ID的代碼提出到組件外,分析了半天,發(fā)現(xiàn)是自己的代碼有問(wèn)題??
如下:
const defaultOptions = [
{ id: getQuestionId('OPTION') },
{ id: getQuestionId('OPTION') },
];
const QuestionRadio: React.FC<{
q: SurveyQuestion;
isEdit: boolean;
index: number;
}> = ({ q, isEdit, index }) => {
const { loading, run, error } = useEditQuestionTitle();
const qdata = (q.qdata || defaultOptions) as SelectOption[];
....
...
}到此這篇關(guān)于react 函數(shù)組件輸入卡頓問(wèn)題 usecallback react.memo的文章就介紹到這了,更多相關(guān)react 函數(shù)組件輸入卡頓內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React項(xiàng)目中hook實(shí)現(xiàn)展示對(duì)話框功能
Modal(模態(tài)框)是 web 開發(fā)中十分常見的組件,即從頁(yè)面中彈出的對(duì)話框,下面這篇文章主要給大家介紹了關(guān)于React項(xiàng)目中hook實(shí)現(xiàn)展示對(duì)話框功能的相關(guān)資料,需要的朋友可以參考下2022-05-05
React組件中使用JSON數(shù)據(jù)文件的方法詳解
要在 React 組件中使用 JSON 數(shù)據(jù),有多種方法,這篇文章主要為大家詳細(xì)介紹了五個(gè)常見的方法,文中的示例代碼講解詳細(xì),有需要的小伙伴可以了解下2024-01-01
react-redux及redux狀態(tài)管理工具使用詳解
Redux是為javascript應(yīng)用程序提供一個(gè)狀態(tài)管理工具集中的管理react中多個(gè)組件的狀態(tài)redux是專門作狀態(tài)管理的js庫(kù)(不是react插件庫(kù)可以用在其他js框架中例如vue,但是基本用在react中),這篇文章主要介紹了react-redux及redux狀態(tài)管理工具使用詳解,需要的朋友可以參考下2023-01-01
解決React報(bào)錯(cuò)Property 'X' does not 
這篇文章主要為大家介紹了解決React報(bào)錯(cuò)Property 'X' does not exist on type 'HTMLElement',有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
淺談React Router關(guān)于history的那些事
這篇文章主要介紹了淺談React Router關(guān)于history的那些事,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
React+Node實(shí)現(xiàn)大文件分片上傳、斷點(diǎn)續(xù)傳秒傳思路
本文主要介紹了React+Node實(shí)現(xiàn)大文件分片上傳、斷點(diǎn)續(xù)傳秒傳思路,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02
react 通過(guò)后端接口實(shí)現(xiàn)路由授權(quán)的示例代碼
本文主要介紹了React應(yīng)用中通過(guò)后端接口獲取路由授權(quán),實(shí)現(xiàn)動(dòng)態(tài)和靈活的權(quán)限管理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-11-11

