我正在处理一些繁重的表格。因此,我想尽可能地压缩性能。最近,我添加了“为什么要渲染”插件,以获取更多有关可能使我的页面变慢的信息。例如,当我单击有关所有其他组件的复选框组件时,我注意到了。理由始终是相同的。 WDYR说
由于道具变更而重新渲染:与道具不同的功能 同名{prev onChangeHandler:ƒ}“!==” {next onChangeHandler:ƒ}
我尽可能地尊重我发现的最佳实践指示。我的组件传递的回调函数遵循这种模式
import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
export function TopLevelComponent({props}){
const defaultData = {name: '', useMale: false, useFemale: false}
const [data, setData] = useState(defData);
const { t } = useTranslation();
const updateState = (_attr, _val) => {
const update = {};
update[_attr] = _val;
setData({ ...data, ...update });
}
const updateName = (_v) => updateState('name', _v);//Text input
const updateUseMale = (_v) => updateState('useMale', _v);//checkbox
const updateUseFemale = (_v) => updateState('useFemale', _v);//checkbox
...
return <div>
...
<SomeInputComponent value={data.name} text={t('fullName')} onChangeHandler={updateName} />
<SomeCheckboxComponent value={data.useMale} onChangeHandler={updateUseMale} text={t('useMale')}/>
<SomeCheckboxComponent value={data.useFemale} onChangeHandler={updateUseFemale} text={t('useFemale')}/>
...
</div>
}
在这样的示例中,更改任何输入(例如:在文本输入中编写文本或单击复选框之一)将导致其他2个组件重新呈现上述理由。
我猜想我可以停止使用功能组件,而使用shouldComponentUpdate()
函数,但是功能组件确实具有一些我宁愿保留的优点。我应该如何以不与一个输入交互的方式来编写函数?
答案 0 :(得分:1)
问题源于您定义变更处理程序的方式:
const updateName = (_v) => updateState('name', _v)
在每次渲染时都会调用此行,因此,每次渲染您的组件时,道具都有一个新的(尽管功能上相同)值。其他所有处理程序也是如此。
作为一种简单的解决方案,您可以将功能组件升级为完全成熟的组件,并将处理程序缓存在render函数之外,也可以在子组件中实现shouldComponentUpdate()
。
答案 1 :(得分:0)
您需要为子组件使用memo
来减少渲染
const SomeInputComponent = props => {
};
export default memo(SomeInputComponent);
// if it still causes rerender witout any prop change then you can use callback to allow or block render
e.f.
function arePropsEqual(prevProps, nextProps) {
return prevProps.name === nextProps.name; // use your logic to determine if props are same or not
}
export default memo(SomeInputComponent, arePropsEqual);
/* One reason for re-render is that `onChange` callback passed to child components is new on each parent render which causes child components to re-render even if you use `momo` because function is updated on each render so in order to fix this, you can use React hook `useCallback` to get the same function reference on each render.
So in you parent component, you need to do something like
*/
import { useCallback } from 'react';
const updateName = useCallback((_v) => updateState('name', _v), [])
答案 2 :(得分:0)
在传递给子代之前,必须先记住父函数,使用useCallback作为功能组件,或者如果使用class,则转换为class属性。
export default class Parent extends React.PureComponent {
constructor(props) {
super(props);
this.onClick = this.onClick.bind(this);
}
onClick() {
console.log("click");
}
render() {
return (
<ChildComponent
onClick={ this.onClick }
/>
);
}
}
with useCallback:
Parent = () => {
const onClick = useCallback(
() => console.log('click'),
[]
);
return (
<ChildComponent
onClick={onClick}
/>
);
}