Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

React doesn't rerender Component after server response

I have a Chat app. I need to rerender the message item (partial Component) after moderator clicks "Delete". So I send a request to the server to make changes in certain message in array of all messages, and response with updated array. Next I set the new array to State using Reducer. As I can see in the logs, state updates after every response, but React doesn’t rerender the message item Component.

Besides, the same code works when I create the new message (example below). Changes on the screen appear only after this sequence: send new message – click "Delete" – send another new message.

Request to the server on "Delete" click:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

axios
  .patch(`${serverName}/messages/${patchTarget}/${messageId}`)
  .then((response) => {
    let fetchedMessages = [...response.data];
    dispatch(setMessages({ fetchedMessages, flag }));
  });

Reducer:

setMessages(state, action) {
  const flag = action.payload.flag;
  // state.showMessages is responsible for showed messages
  state[flag] = [...action.payload.fetchedMessages];
  state.showMessages[flag] = [...state[flag]];
}

Server:

let MESSAGES = {
  DISPUTE: [{}],
  SPEC: [{}]
};

app.get("/messages/:target", (req, res) => {
  const fetchTarget = req.params.target;
  res.status(200).json(MESSAGES[fetchTarget as keyof typeof MESSAGES]);
});

app.post("/messages/:target", (req, res) => {
  const newMessage = req.body;
  const pushTarget = req.params.target;
  MESSAGES[pushTarget as keyof typeof MESSAGES].push(newMessage);
  res.status(200).json(MESSAGES[pushTarget as keyof typeof MESSAGES]);
});

app.patch("/messages/:target/:id", (req, res) => {
  const patchTarget = req.params.target;
  const messageId = Number(req.params.id);
  const element = MESSAGES[patchTarget as keyof typeof MESSAGES][messageId];
  if (!element.deletedText) element.deletedText = element.text;
  if (!element.deleted) element.deleted = !element.deleted;
  element.text = "Message has been deleted by moderator";
  
  res.status(200).json(MESSAGES[patchTarget as keyof typeof MESSAGES]);
});

Working code in another Component where I create a new message and send it:

axios
  .post(`${serverName}/messages/${pushTarget}`, newMessageFunc())
  .then((response) => {
  let fetchedMessages = [...response.data];
  dispatch(setMessages({ fetchedMessages, flag }));
});

Why does it work when I create a new message, but it doesn’t when I try to edit it?

>Solution :

As long as the data are all right, most likely the issue will be on the front-end side.

There is a lot of unknowns how does this code actually work, but most likely it’s the problem with detecting the change in state.

When you have your reducer:

setMessages(state, action) {
  const flag = action.payload.flag;
  // state.showMessages is responsible for showed messages
  state[flag] = [...action.payload.fetchedMessages];
  state.showMessages[flag] = [...state[flag]];
}

The arrays have new identity, but the showMessages object is still the same – it may cause the change being not detected. The React will try to find a change by identity check (===), not by deep equality check (i.e. lodash‘s isEqual). Assuming that previous state is prevState and the state after reducer is nextState:

prevState[flag] === nextState[flag] // false
prevState.showMessages === nextState.showMessages // true
prevState.showMessages[flag] === nextState.showMessages[flag] // false

Most likely, if you’ll change your reducer to create a new showMessages object, it will work fine:

setMessages(state, action) {
  const flag = action.payload.flag;
  // state.showMessages is responsible for showed messages
  state[flag] = [...action.payload.fetchedMessages];
  state.showMessages = {
    ...state.showMessages,
    [flag]: [...state[flag]],
  };
}

After that, all objects will be detected as different from the previous state:

prevState[flag] === nextState[flag] // false
prevState.showMessages === nextState.showMessages // false
prevState.showMessages[flag] === nextState.showMessages[flag] // false
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading