【发布时间】:2020-10-19 15:51:22
【问题描述】:
我正在屏幕上生成一个组件列表,如下所示:
const MessagesContainer = ({ messages, categories, addHandler }) => {
const options = categories.map(category => (
{ value: category.name, label: category.name }
));
return (
<div className="d-flex flex-wrap justify-content-center">
{messages.map(message =>
<div key={message.id}>
<MessageEditor
message={message}
options={options}
addHandler={addHandler}
/>
</div>
)}
</div>
);
};
const MessageEditor = ({ message, options, addHandler }) => {
const [modifedMessage, setModifiedMessage] = useState(message);
const [isAdded, setIsAdded] = useState(false);
const textClass = (charLimit - modifedMessage.text.length) > 0 ?
'text-success' : 'text-danger';
const buttonClass = isAdded ? 'danger' : 'primary';
const ref = useRef(null);
const textAreaHandler = textArea => {
const copiedMessage = { ...modifedMessage };
copiedMessage.text = textArea.target.value;
setModifiedMessage(copiedMessage);
};
const addButtonHandler = () => {
const add = !isAdded;
setIsAdded(add);
let selectedCategoires = ref.current.state.value;
// Firing this handler results in ALL the MessageEditor
// componets on the screen being re-rendered
addHandler(modifedMessage, add, selectedCategoires);
}
return (
<div className="d-flex flex-column message-view-container ml-5 mr-5 mb-5">
<div className={`message-count-container ${textClass}`}>
{charLimit - modifedMessage.text.length}
</div>
<Select
ref={ref}
placeholder="Tags"
isMulti
name="tags"
options={options}
defaultValue={[options[0]]}
className="basic-multi-select select-container"
classNamePrefix="select"
isDisabled={isAdded}
/>
<Form.Control
style={{
width:350,
height:220,
resize:'none'
}}
className="mb-1"
as="textarea"
defaultValue={message.text}
onChange={textAreaHandler}
disabled={isAdded}
/>
<Button variant={buttonClass} onClick={addButtonHandler}>
{isAdded ? 'Remove' : 'Add'}
</Button>
</div>
);
};
以及持有addHandler的父组件:
const { useState } = require("react");
const Messages = () => {
const [messages, setMessages] = useState([]);
const [saveMessages, setSaveMessages] = useState({});
const addHandler = (modifiedMessage, add, selectedCategoires) => {
const copiedSaveMessages = { ...saveMessages };
if (add) {
if (selectedCategoires) {
selectedCategoires = selectedCategoires.map(item => item.value);
}
copiedSaveMessages[modifiedMessage.id] = {
text: modifiedMessage.text,
tags: selectedCategoires ? selectedCategoires : []
}
} else {
delete copiedSaveMessages[modifiedMessage.id];
}
// This results in every single MessageEditor component being
// re-rendered
setSaveMessages(copiedSaveMessages);
};
return (
<div>
{categories &&
<div>
<div className="ml-5 mr-5 mt-5">
<MessagesContainer
messages={messages}
categories={categories}
addHandler={addHandler}
/>
</div>
</div>
}
{Object.keys(saveMessages).length > 0 &&
<div>
<Image
className="upload-icon"
src={uploadIcon}
/>
<div className="text-primary count-container">
<h2>{Object.keys(saveMessages).length}</h2>
</div>
</div>
}
</div>
);
};
问题是,如果我点击添加按钮触发addHandler,它会导致所有MessageEditor 组件重新渲染。如果屏幕上有几百个组件,性能会很慢。
我猜这是因为saveMessages 状态变量属于Messages 组件,而MessageEditor 是Messages 的子级,所以它也会重新渲染。
有没有一种方法可以在不导致所有其他组件重新渲染的情况下更新此状态?
【问题讨论】:
-
你能创建一个沙盒问题吗?衡量有形性的表现会更好吗?
标签: javascript reactjs