skip to Main Content

I’m building chat app using ReactJS, NestJS, Socket.io .

And it’s multi channel using rooms in socket.io

const [messages, setMessages] = useState({
        ReactJS: [],
        NestJS: [],
        Typescript: [],
        MySQL: [],
        Neo4j: [],
        Redis: [],
        ELK: [],
        Docker: [],
        Kubernetes: [],
        AWS: [],
        SocketIO: [],
    });

This is array with useState for pushing message.

Question

messages['ReactJS'].push(someMessage);

How useState push element to array inside object?

2

Answers


  1. Given the state

    const [messages, setMessages] = useState({
      ReactJS: [],
      NestJS: [],
      Typescript: [],
      MySQL: [],
      Neo4j: [],
      Redis: [],
      ELK: [],
      Docker: [],
      Kubernetes: [],
      AWS: [],
      SocketIO: [],
    });
    

    Then the following is a way to update a specific room via a roomKey identifier nested in the state object. In React when you update state you must always return a new object reference, and this includes any nested state/properties that are being updated. array.prototype.push mutates the original array, it doesn’t create a new array reference for React purposes.

    setMessages(messages => ({
      ...messages, // <-- shallow copy state
      // copy existing nested state array into new array and append new element
      [roomKey]: [...messages[roomKey], newMessage],
    }));
    

    An alternative to the array literal is to use array.prototype.concat, which does return a new array.

    setMessages(messages => ({
      ...messages, // <-- shallow copy state
      // copy existing nested state array into new array and append new element
      [roomKey]: messages[roomKey].concat(newMessage),
    }));
    

    Note: This assumes your roomKey variable will reference one of the keys actually defined in your state. If you use an unspecified key then messages[unknownKey] will be undefined. In this case, if you’ve truly dynamic keys, then you can provide a fallback value to spread into state.

    setMessages(messages => ({
      ...messages, // <-- shallow copy state
      // copy existing nested state array into new array and append new element
      [roomKey]: [
        ...messages[roomKey] || [], // <-- provide fallback
        newMessage,
      ],
    }));
    
    Login or Signup to reply.
  2. If you can install some additional utilities here are some other way to do it

    Ramda

    rootPath = 'ReactJS'
    const newArray = R.append(someMessage, messages[rootPath])
    const newMessages = R.assocPath([rootPath], newArray, messages);
    setMessages(newMessages)
    
    // combined
    const rootPath = 'ReactJS'
    setMessages(
        R.assocPath(
            [rootPath],
            R.append(
                someMessage,
                messages[rootPath]
            ),
            messages
        )
    )
    

    Immerjs

    import produce from 'immer'
    
    const rootPath = 'ReactJS'
    const newMessages = produce(messages, draftState => {
        draftState[rootPath].push = someMessage
    })
    
    setMessages(newMessages)
    
    // combined
    import p from 'immer'
    
    const rootPath = 'ReactJS'
    setMessages(p(messages, draft => {
        draft[rootPath].push = someMessage
    }))
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search