reactjs - 即使没有更新,useEffect 也会不断重新渲染组件
问题描述
请帮助我是新来的反应。我正在尝试创建一个简单的消息传递应用程序。
我希望 MessageForm 组件在 [messages] 有更新时稍微重新呈现。它会这样做,但即使没有更新也不会停止。
我知道这一点,因为当我检查我的 redux 开发工具时,我不断重复看到一个动作
const MessageForm = ({ getMessages, addMessages, deleteMessages, messages, roomId,}) => {
useEffect(() => {
getMessages(roomId);
scrollToBottom();
}, [messages]);
const [formData, setFormData] = useState({
text: "",
});
const { text } = formData;
let messagesEnd;
const scrollToBottom = () => {
messagesEnd.scrollIntoView({ behavior: "smooth" });
};
const onChange = (e) =>
setFormData({ ...formData, [e.target.name]: e.target.value });
const onSubmit = (e) => {
e.preventDefault();
addMessages(text, roomId);
setFormData({ text: "" });
};
let user = JSON.parse(localStorage.getItem("user"));
let messageList = messages.messages.map((message) => {
return message.user === user._id ? (
<div className="row">
<div className="container darker col-6" key={message._id}>
<div className="username"> {message.name}</div>
<Avatar
size="50"
round={true}
src={message.avatar}
className="right"
/>
<p>{message.text.toString()}</p>
<span className="time-left">
{moments(message.createdAt).format("LLL")}
</span>
<span className="time-right">
<Icon
onClick={() => {
deleteMessages(message._id);
}}
name="trash alternate"
className="trashCan"
/>
</span>
</div>
</div>
) : (
<div className="row justify-content-end">
<div className="container darker senders col-6 " key={message._id}>
<div className="username"> {message.name}</div>
<Avatar
size="50"
round={true}
src={message.avatar}
className="right"
/>
<p>{message.text.toString()}</p>
<span className="time-left">
{moments(message.createdAt).format("LLL")}
</span>
<span className="time-right">
<Icon
onClick={() => {
deleteMessages(message._id);
}}
name="trash alternate"
className="trashCan"
/>
</span>
</div>
</div>
);
});
return (
<div className="messageArea">
<div className="textarea">
{messageList}
<div
style={{ float: "left", clear: "both" }}
ref={(el) => {
messagesEnd = el;
}}
></div>
</div>
<form className="row inputBox" onSubmit={onSubmit}>
<div className="col-10">
<input
type="text"
className="form-control"
placeholder="Enter Message"
aria-label="Enter Message"
aria-describedby="basic-addon2"
id="text"
value={text}
name="text"
onChange={onChange}
/>
</div>
<div className="col-2">
<button className="btn btn-outline-secondary" type="submit">
Send
</button>
</div>
</form>
</div>
);
};
const mapDispatchToProps = (dispatch) => ({
addMessages: (text, roomId) => dispatch(addMessages(text, roomId)),
getMessages: (roomId) => dispatch(getMessages(roomId)),
deleteMessages: (id) => dispatch(deleteMessages(id)),
});
const mapStateToProps = (state, props) => ({
messages: state.messages,
roomId: props.location.state.roomId,
});
export default connect(mapStateToProps, mapDispatchToProps)(MessageForm);
解决方案
有两个问题。
- 您正在调用
getMessages
,一个可能同时更新messages
两者的方法是道具,如果一个更改,整个组件将更新。useEffect 不控制父组件,因此每次父组件更新时,子组件也会更新。 - 第二个问题是您调用一个方法,
useEffect
该方法将 reloadmessages
,然后它将useEffect
再次调用。
我会通过getMessages
移出这个组件来解决这个问题,或者我会放一个 if 语句useEffect
来看看你是否需要调用getMessages
.