Home > Software design >  React native: how do I wait for a state to be set, before I call another state related operation?
React native: how do I wait for a state to be set, before I call another state related operation?

Time:03-03

I am writing a chat app. Users can search for other users, and then press the "Message" button. Then I navigate to ChatScreen.js. If both users have been messaging each other, I set the chatId variable accordingly. If they have not messaged each other before I dont create chatId, until the ery first message has been sent. When the first message is sent, I first, create new chat, store its properties (user ids, chatId, etc) in my db and then I sent the first message. The problem is that I store chatId as a state variable, and when I create the chat I call setChatId(id). setChatId() is not synchronous call, so by the time when I need to send message with sendText(text, chatId); my chatId is undefined even though I have already created a chat and I have called setChatId.

How can I avoid this error? Ofc, I can check if chatId == undefined then calling sendText(text, id), otherwise calling sendText(text, chatId). Is there a better/neath way to avoid the undefined check?

Here is part of my code:

...

import {
  createChat,
} from "./actions";

...

function ChatScreen(props) {
  ...
  const [chatId, setChatId] = useState(props.route.params.chatId);
  ...

  const setupChat = async () => {
    try {
      await createChat(user.id, setChatId);
      props.fetchUserChats();
    } catch (error) {
      console.error("Error creating chat: ", error);
    }
  };

  async function handleSend(messages) {
    if (!chatId) {
      // creating chat
      await setupChat();
    }
    const text = messages[0].text ? messages[0].text : null;
    const imageUrl = messages[0].image ? messages[0].image : null;
    const videoUrl = messages[0].video ? messages[0].video : null;
    const location = messages[0].location ? messages[0].location : null;
    //assuming chatId is already setup but it is not
    if (imageUrl) {
      sendImage(imageUrl, chatId, setSendImageError);
    } else if (location) {
      sendLocation(location, chatId, setLocationError);
    } else if (videoUrl) {
      sendVideo(videoUrl, chatId, setSendImageError);
    } else {
      sendText(text, chatId);
    }

  }

...
}

My createChat function from actions.js file

export async function createChat(otherUid, setChatId) {
  let chatId = firebase.auth().currentUser.uid   "_"   otherUid;
  await firebase
    .firestore()
    .collection("Chats")
    .doc(chatId)
    .set({
      users: [firebase.auth().currentUser.uid, otherUid],
      lastMessage: "Send the first message",
      lastMessageTimestamp: firebase.firestore.FieldValue.serverTimestamp(),
    })
    .then(() => {
      console.log("doc ref for creatign new chat: ", chatId);
      setChatId(chatId);
    })
    .catch((error) => {
      console.error("Error creating chat: ", error);
    });
}

CodePudding user response:

Instead of using a state variable, I would advise you to use useRef(). This would be a good solution to your problem.Eg Define it this way const chatId = useRef(null),

then set it this way chatId.current = yourChatId

and get it this way chatId.current. I hope this solves your problem

  • Related