Home > Enterprise >  Component not displaying updated data when field is updated?
Component not displaying updated data when field is updated?

Time:09-26

I have a table that is populated with data from an array of objects.

This data is collected via websockets. The socket listens to 3 different events, and does one of the following to the array based on the event:

  1. User can add an entry - ✅ works fully
  2. User can modify an entry - issue
  3. User can delete an entry - ✅ works fully

Here is the code:

interface TableEntry {
  address: string;
  amount: string;
  children?: React.ReactNode;
}

export const TableComponent: FC = () => {
  const socket = useContext(SocketContext);
  const [entriesArray, setEntriesArray] = useState<TableEntry[]>([]);
  const { globalAddress } =
    useContext(UserDetailsContext);

  useEffect(() => {
    socket.on("end", (data) => {
      setEntriesArray([]);
    });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    var tempEntries = entriesArray;
    socket.on("entry", (data) => {
      tempEntries.push({ address: data[0], amount: data[1] });
      setEntriesArray(tempEntries);
      tempEntries = [];
    });
    return function () {
      socket.off("entry");
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  //Update an entry on request from a user
  useEffect(() => {
    var tempEntries = entriesArray;
    socket.on("updateEntry", (data) => {
      const findFunc = (element: TableEntry) => element.address == data[0];
      const index = tempEntries.findIndex(findFunc);

      tempEntries[index].address = "updated address";

      setEntriesArray(tempEntries);
      tempEntries = [];
    });
    return function () {
      socket.off("updateEntry");
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

return (
    <>
      <Box>
        <Box
          w="427px"
          h="450px"
          top={"72px"}
          right={"60px"}
          bg={"rgba(255, 255, 255, 0.08)"}
          position={"absolute"}
          borderRadius="21"
          overflow="hidden"
        >
          <TableContainer>
            <Table variant="simple">
              <Thead>
                <Tr>
                  <Th fontFamily={"Orbitron"}>Address</Th>
                  <Th fontFamily={"Orbitron"}>Amount</Th>
                </Tr>
              </Thead>
              <Tbody>
                {entriesArray?.map((entry) => {
                  return entry.address == globalAddress ? (
                    <Tr key={entry.address} bg={"rgba(255, 255, 255, 0.05)"}>
                      <Td fontFamily={"Orbitron"}>{shorten(entry.address)}</Td>
                      <Td fontFamily={"Orbitron"}>{entry.amount}</Td>
                    </Tr>
                  ) : (
                    <Tr key={entry.address}>
                      <Td fontFamily={"Orbitron"}>{shorten(entry.address)}</Td>
                      <Td fontFamily={"Orbitron"}>{entry.amount}</Td>
                    </Tr>
                  );
                })}
              </Tbody>
            </Table>
          </TableContainer>
        </Box>
      </Box>
    </>
  );
};

The data updates, but it is not being displayed in the table - how can I make sure the data in the table reflects the update?

I assumed since I am changing the state of entriesArray that forced a rerender - but that doesn't seem to be the case?

CodePudding user response:

React's state is immutable, so you cannot update an array item directly. You need to use map with {...element} for cloning and updating that array item at the same time.

useEffect(() => {
  socket.on("updateEntry", (data) => {
    const tempEntries = entriesArray.map((element: TableEntry) =>
      element.address == data[0]
        ? { ...element, address: "updated address" } //update the found element
        : element //keep the original element
    );

    setEntriesArray(tempEntries);
    tempEntries = [];
  });
  return function () {
    socket.off("updateEntry");
  };
  // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

Note that, you also can clone the entire array with a spread operator like [...entriesArray] or cloneDeep before updating any element, but it's not preferable because it means you want to render the entire array (even though you want to render the updated element only) which hits performance if you have a huge array.

CodePudding user response:

You are mutating the original state array. when you type var tempEntries = entriesArray; you just made the tempEntries points to the same state object for creating a new object in your case it's an array you can do this

let tempEntries = [...entriesArray];
  • Related