首页 > 解决方案 > 即使没有更新,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);

标签: reactjs

解决方案


有两个问题。

  1. 您正在调用getMessages,一个可能同时更新messages两者的方法是道具,如果一个更改,整个组件将更新。useEffect 不控制父组件,因此每次父组件更新时,子组件也会更新。
  2. 第二个问题是您调用一个方法,useEffect该方法将 reload messages,然后它将useEffect再次调用。

我会通过getMessages移出这个组件来解决这个问题,或者我会放一个 if 语句useEffect来看看你是否需要调用getMessages.


推荐阅读