1

suppose we try to connect web socket. web socket server sends some data for fetching client status which represents the online or offline. I tried to store these data into redux (works fine), but I need to change these statuses instantly with overriding the existing objects. I need some functionality for override my redux store. I get so far with the snippet below.

but:

this code push objects to my redux store not overriding

  const [status, set_status] = useState([]);

  useEffect(() => {
    const socket = io(ws_api, {
      query: `token=${localStorage.getItem("token")}`,
    });

    socket.on("message", (data) => {

      status.map((item) => {
        if (item.application === data.application) {
          item["status"] = data.status;
        } else {
          set_status((status) => [...status, data]);
        }
      });

    });
  }, []);

  useEffect(() => {
    get_client_status(status); // redux action
  }, [status]);

the data structure which is coming from the socket on message

{
  application: "5ede25f4d3fde1c8a70f0a38"
  client: "5ede25f4d3fde1c8a70f0a36"
  status: "offline"
}
Amin Azimi
  • 659
  • 9
  • 25

1 Answers1

1

First search current state for any existing data elements, if found then update it, otherwise add to the array.

Using array::findIndex

const messageHandler = data => {
  const dataIndex = status.findIndex(
    item => item.application === data.application
  );

  if (dataIndex !== -1) {
    set_status(status =>
      status.map(item => {
        return item.application === data.application
          ? { ...item, status: data.status }
          : item;
      })
    );
  } else {
    set_status(status => [...status, data]);
  }
});

Using array::find

const messageHandler = data => {
  const found = status.find(item => item.application === data.application);

  if (found) {
    set_status(status =>
      status.map(item => {
        return item.application === data.application
          ? { ...item, status: data.status }
          : item;
      })
    );
  } else {
    set_status(status => [...status, data]);
  }
});

Edit: define this callback outside the effect

useEffect(() => {
  socket.on("message", messageHandler);
}, []);
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
  • because this block of code is inside the use effect (componentDidMount) every time that message is coming return -1 I don't know how it will go to fixed – Amin Azimi Jun 20 '20 at 06:17
  • Ah yeah, the `onMessage` callback is enclosed in the scope, along with the state value when mounted. Try defining the data handler callback outside the effect. I'll update answer. – Drew Reese Jun 20 '20 at 06:21
  • the data handler callback outside the effect just push objects into array not override :( – Amin Azimi Jun 20 '20 at 06:50
  • @MA2WEB You know what, re-reading your question I see you're maintaining duplicate state if you are sending the messages to be stored there *and* keeping them in local component state. Are you saying the data in your redux store isn't overriding? I think the solution is to `onMessage` send the message in an action to a reducer to update your state. The logic would be mostly the same and you'd be updating your single source of truth. – Drew Reese Jun 20 '20 at 06:57