ReactJS: первый useEffect не обновляет состояние до срабатывания второго - PullRequest
0 голосов
/ 20 апреля 2020

У меня есть компонент Chat, который использует API для заполнения состояния messages, также есть разные области, в которых есть разные чаты, которые я передаю как реквизиты для компонента.

В этом компоненте у меня есть 3 useEffects но меня интересуют два из них, которые не работают должным образом. В первом useEffect у меня есть код, который в основном сбрасывает состояние messages при изменении области на undefined. Мне нужно сделать это, чтобы иметь возможность различать guish между API, который еще не вызывается, где я отображаю загрузочный компонент <Spinner />, или если был вызван API, и он получил пустой массив для отображения <NoData> компонент.

Проблема, с которой я столкнулся, заключается в том, что когда я меняю области, useEffects запускается так, как должен, но первый useEffect не обновляет состояние messages до неопределенного, прежде чем второй useEffect называется. И после повторного рендеринга из-за истории pu sh сообщения приходят как неопределенные, но затем второй useEffect больше не срабатывает. Я не понимаю, почему состояние не обновляется в первом useEffect до второго. Также странно то, что раньше это работало на меня раньше, а теперь нет. Я изменил некоторые вещи, не нажимая на git, и теперь я озадачен. Код ниже:

export default function ChatPage({ history, match, area, ...props }) {
  const [templates, setTemplates] = useState([]);
  const [advisors, setAdvisors] = useState([]);
  const [messages, setMessages] = useState(undefined);
  const [conversation, setConversation] = useState([]);
  const [chatToLoad, setChatToLoad] = useState(false);
  const [isOpen, setIsOpen] = useState(false);
  const [linkOrigin, setLinkOrigin] = useState("");
  const [headerText, setHeaderText] = useState("");

  // useEffect used to reset messages and conversation state
  // triggered on area change(messages and conversation reset)
  // and customer ID change(conversation reset).
  // Required to distinguish between API call not being made yet
  // and API returning no data.
  useEffect(() => {
    if (match.params.id) {
      setLinkOrigin(match.params.id);
    }

    if (messages) {
      if (match.params.id && messages.length !== 0) {
        let matches = messages.filter(
          (message) => message.ORIGINATOR === match.params.id
        );

        if (matches.length !== 0 && match.params.id === linkOrigin) {
          setMessages(undefined);
          history.push("/chats/" + match.params.area);
        }
      }
    }

    setConversation([]);
  }, [area, match.params.id]);

  // API calls
  useEffect(() => {
    if (templates.length === 0) {
      api.getTemplates().then((templates) => {
        setTemplates(templates);
      });
    }

    if (advisors.length === 0) {
      api.getAgents().then((advisors) => {
        setAdvisors(advisors);
      });
    }

    if (!messages || messages.length === 0) {
      chooseQueue(match.params.area).then((queuesData) => {
        let queues = queuesData.data.map((message) => ({
          DATE_SORT: message.DATE_RECIEVED,
          UNIQUEID: message.UNIQUEID,
          ORIGINATOR: message.ORIGINATOR,
          MESSAGE: message.MESSAGE,
          MSG_TYPE: "SMS_OUTBOUND",
          ASSIGNED_TO: message.ASSIGNED_TO || null,
        }));

        setMessages(orderMessagesByDate(queues));
        setChatToLoad(queues[0]);
      });
    }
  }, [area]);

  useEffect(() => {
    if (messages) {
      if (messages.length) {
        let loadId = match.params.id ? match.params.id : messages[0].ORIGINATOR;

        const params = {
          MobileNumber: loadId,
        };
        messagingApi.conversationHistory(params).then((conversationData) => {
          setConversation(
            conversationData.data.map((message) => ({
              DATE_SORT: message.DATE_SORT,
              UNIQUEID: message.UNIQUEID,
              ORIGINATOR: message.ORIGINATOR,
              MESSAGE: message.MESSAGE,
              MSG_TYPE: message.MSG_TYPE2.replace("MobileOriginated", "SMS"),
              ASSIGNED_TO: message.ASSIGNED_TO || null,
            }))
          );
        });

        setChatToLoad(
          messages.find((message) => message.ORIGINATOR === loadId)
        );
        history.push("/chats/" + match.params.area + "/" + loadId);
      }
    }
  }, [messages]);

  function chooseQueue(queueType) {
    switch (queueType) {
      case "myqueue":
        setHeaderText("My chats");
        return queuesApi.getMyActiveQueues(area);
      case "mycompleted":
        setHeaderText("My completed chats");
        return queuesApi.getMyCompletedQueues();
      case "queues":
        setHeaderText("Chats");
        return queuesApi.getQueues(area);
      case "completed":
        setHeaderText("Completed chats");
        return queuesApi.getCompletedQueues();
      default:
        setHeaderText("My chats");
        return queuesApi.getQueues(area);
    }
  }

  function classifyMessage(message) {
    return message.MSG_TYPE.includes("OUTBOUND") ||
      message.MSG_TYPE.includes("FAULT_TEST")
      ? "outbound"
      : "inbound";
  }

  async function submitMessage(message) {
    var params = {
      number: message.ORIGINATOR,
      message: message.MESSAGE,
      smssize: message.MESSAGE.length
    };
    await messagingApi.replyToCustomer(params).then((res) => {
      if (res.data[0].RVALUE === "200") {
        let extendedMsg = [...messages, message];
        let extendedConversation = [...conversation, message];
        setConversation([...extendedConversation]);
        setMessages(orderMessagesByDate([...extendedMsg]));
      }
    });
  }

  function orderMessagesByDate(list) {
    return list.sort(function(x, y) {
      return new Date(y.DATE_SORT) - new Date(x.DATE_SORT);
    });
  }

  const modalHandler = () => {
    setIsOpen(!isOpen);
  };

  let chatConfig = {
    channelSwitch: true,
    channels: channels,
    templateModal: true,
    templates: templates,
    advisorModal: true,
    advisors: advisors,
  };

  const onActiveChatChange = (message) => {
    history.push("/chats/" + match.params.area + "/" + message.ORIGINATOR);

    const params = {
      MobileNumber: message.ORIGINATOR,
    };
    messagingApi.conversationHistory(params).then((conversationData) => {
      setConversation(
        conversationData.data.map((message) => ({
          DATE_SORT: message.DATE_SORT,
          UNIQUEID: message.UNIQUEID,
          ORIGINATOR: message.ORIGINATOR,
          MESSAGE: message.MESSAGE,
          ASSIGNED_TO: message.ASSIGNED_TO || null,
        }))
      );
    });
  };

  return (
    <div data-test="component">
      <BodyHeader
        text={headerText}
        children={
          <FontAwesomeIcon
            icon="plus-square"
            aria-hidden="true"
            size="2x"
            onClick={modalHandler}
          />
        }
      />
      {messages && chatToLoad ? (
        <>
          <ChatWindow
            messages={messages}
            conversation={conversation}
            chatToLoad={chatToLoad}
            onActiveChatChange={onActiveChatChange}
            classifyMessage={classifyMessage}
            submitMessage={submitMessage}
            config={chatConfig}
          />
          <SendMessageModal isOpen={isOpen} toggle={modalHandler} />
        </>
      ) : !messages ? (
        <Spinner />
      ) : (
        <NoDataHeader>There are no chats in this area</NoDataHeader>
      )}
          
    </div>
  );
}

1 Ответ

0 голосов
/ 20 апреля 2020

Вы не можете получить то, что вы хотите таким образом. Изменение состояния, примененное в useEffect, не будет действовать до следующего цикла рендеринга. Следующие обратные вызовы по-прежнему будут видеть текущее значение const. Если вы хотите изменить значение в текущем цикле рендеринга, единственный вариант, который у вас есть, - это ослабить константное значение в let и установить переменные самостоятельно.

В конце концов: вы ожидали, что константа изменится, не так ли ? ;)

...