reactjsreact-nativeuuidreact-native-gifted-chatnanoid

Problem with generating random Id in react-native with Nanoid or UUID


I have a chat app, when I create for the first time a new chat I need an random Id to identify the chat, then, when I try to send the message I need that same id. I declare nanoId before the component declaration:

  import "react-native-get-random-values";
  import { nanoid } from "nanoid";

  const randomId = nanoid()
  export default function Chat({navigation, route}) {

    const [messages, setMessages] = useState([]); //messages array
    const [roomHash, setRoomHash] = useState(""); 
 
    const {user} = useUserAuth(); //authenticated user from the context provider
    const contact = route.params.contact;
    const room = route.params.room;
    console.log(randomId)
    const roomId = room ? room.id : randomId`

All works fine, I create the chat correctly, I can even send the messages correctly because it is kept with the same id that was used to create the chat.

the problem comes when I navigate to home and try to create a new second chat, the problem is it keeps the first ID, it is like it never change after the first time. So, how can I get a new random id every time I open the chat screen?


Solution

  • To have an answer instead of a comment:

    Declaring a randomId in a way you did is just a normal way to have normal constants, they will not be changed until browser page reload. As you said, "it never change after the first time".

    What can be done: Use the useMemo hook to get a value that is evaluated only 1 on component mount and is persistent during rerenders due to depsArray is empty, [].

    const randomId = useMemo(() => nanoid(), []);
    

    Also you can wrap the roomId with same useMemo hook. Cons - react will raise a warning about "useMemo has a complex expression in the dependency array"

    // will be triggered only when room.id (string) is changed
    // Changing the room from 1 with id=null to 2 with id=0 
    // will not trigger this hook (and your code in question will act in same way also)
    const roomId = useMemo(() => {
      return room?.id || nanoid();
    }, [room?.id]) 
    

    Everything from above can be easilly replaced with useState + useEffect hooks, but useMemo is just like shorter.

    But with that im a bit concerned about const roomId = room ? room.id : randomId logic overall for a few cases:

    1. in case you had room without an Id, texted something there, then switched to another room without an Id without unmounting (destroying) a Chat component itself - for both those rooms without Id the randomId (roomId) will be the same.

    2. In case the component is mounted but room is null or undefined - roomId still will be set and that would be strange to me.

    I dont think it is possible to handle those scenarios right in this Chat component.

    In my opinion the room object should be completely prepared and initialized (and room id set) before passing it down to the Chat component, so Chat will get a non-nullable Room object with Id set. In terms of architecture Components should be as "dumb" as possible and should only depends on the state management systems, like Contexts, for example.