Home > database >  React doesn't rerender Component after server response
React doesn't rerender Component after server response

Time:06-27

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:

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?

CodePudding user response:

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
  • Related