javascript - 如何防止在 React 中重新渲染整个组件?
问题描述
我有一个模态组件,它是 3 个 Tab 组件的父级。formData 是 Modal 组件状态的一部分,并将其传递给它的子组件。问题是,每当任何选项卡中的任何字段发生更改时,都会触发整个 Modal 组件及其子组件的重新渲染,从而使表单有点滞后。
我的印象是 React 只会重新渲染实际 DOM 和虚拟 DOM 之间存在的任何差异?有没有解决的办法?
Codesandbox最小示例
解决方案
我对您的代码进行了一些更改,因此当详细信息更改时联系人不会重新呈现,反之亦然。
//Wrap functional component Details in React.memo
const Details = React.memo(function Details({
formData: { title, description },
onChange,
}) {
console.log('render details');
return (
<React.Fragment>
<input
value={title}
onChange={({ target: { value } }) =>
onChange(value, 'details', 'title')
}
/>
<input
value={description}
onChange={({ target: { value } }) =>
onChange(value, 'details', 'description')
}
/>
</React.Fragment>
);
});
//Make Contact also pure with React.memo
const Contact = React.memo(function Contact({
formData: { name, number },
onChange,
}) {
console.log('render contact');
return (
<React.Fragment>
<input
value={name}
onChange={({ target: { value } }) =>
onChange(value, 'contact', 'name')
}
/>
<input
value={number}
onChange={({ target: { value } }) =>
onChange(value, 'contact', 'number')
}
/>
</React.Fragment>
);
});
const Create = () => {
const [formData, setFormData] = React.useState({
details: {
title: '',
description: '',
},
contact: {
name: '',
number: '',
},
});
//only create onChange once (empty dependencies for useCallback)
const onChange = React.useCallback(
(value, tab, field) => {
//you were mutating and not using callback for state
// setting causing unnecessary dependency for useCallback
setFormData(current => ({
...current,
[tab]: {
...current[tab],
[field]: value,
},
}));
},
[]
);
return (
<React.Fragment>
{/* instead of passing the entire formData, only pass
the part that it actually needs so when Contact changes
Details isn't re rendered because you're passing an object
that has changed you pass object containing contact to details
and object contact details to details */}
<Details
formData={formData.details}
onChange={onChange}
/>
<Contact
formData={formData.contact}
onChange={onChange}
/>
</React.Fragment>
);
};
ReactDOM.render(
<Create />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
推荐阅读
- macos - VoiceProcessingIO 音频单元将意外的输入流添加到内置输出设备 (macOS)
- node.js - 如何使用 JSDoc 声明 mongodb 集合
- rxjs - 使用 RxJS 延迟一批 observables
- reactjs - React - 简单的 ul li 过滤器
- javascript - JS 函数翻倍
- python-3.x - 使用漂亮的汤解析 SGML
- php - 如何通过 PHPmailer 将附件从 Laravel 存储应用程序发送到电子邮件
- android - 如何在动态芯片添加方法中一个接一个地垂直对齐芯片组项目
- javascript - 如何在formData中传递一个数组
- typescript - 找不到模块:错误:无法解析“./types/string”