使用仅添加一个元素的套接字更新 mui 数据网格

Update mui data-grid with socket only one element added

我在使用 mui 数据网格和 socket.io 时遇到问题。 我从 api 加载初始数据,效果很好。 但是当我想用来自 websocket 的数据更新 table 时,每次更改时只添加并覆盖一个元素。代码如下:

Table:

const [tableData, setTableData] = useState(props.tableData);

useEffect(() => {
    setTableData(props.tableData);
  }, [props.tableData]);

return (<div key="tradingTableGrid" style={{ height: 450, width: "100%" }}>
          <DataGrid
            key={"TradingTable"}
            rows={Object.values(tableData)}
            columns={tableHead}
            rowHeight={30}
            pageSize={10}
            onRowClick={(row) => openModal(row)}
          />
</div>);

加载初始数据和调用 websocket 更新的组件如下(我只添加了必要的代码):

const [data, setData] = useState({});
const [loadData, setLoadData] = useState(false);
const [socketActive, setSocketActive] = useState(false);

// initial data loading from api
const handleResponse = (response) => {
  var result = {};
  response.forEach((prop) => {
    result = {
      ...result,
      [prop.order_id]: {
        id: prop.order_id,
        orderId: prop.order_id,
        price: prop.price.toString(),
        volume: prop.max_amount_currency_to_trade,
        minVolume: prop.min_amount_currency_to_trade,
        buyVolume: prop.max_volume_currency_to_pay + " €",
        minBuyVolume: prop.min_volume_currency_to_pay + " €",
        user: prop.trading_partner_information.username,
      },
    };
  });
  setData(result);
};

// add from websocket
const addOrder = (order) => {
  if (
    order.trading_pair === "btceur" &&
    order.order_type === "buy" &&
    (order.payment_option === "1" || order.payment_option === "3")
  ) {
    if (typeof data[order.order_id] === "undefined") {
      console.log(data);
      setData({
        ...data,
        [order.order_id]: {
          id: order.order_id,
          orderId: order.order_id,
          price: order.price.toString(),
          volume: order.amount,
          minVolume: order.min_amount,
          buyVolume: Number(order.volume).toFixed(2) + " €",
          minBuyVolume: Number(order.min_amount * order.price).toFixed(2) + " €",
          user: "not set through socket",
        },
      });
    }
  }
};

useEffect(() => {
  const loadData = () => {
    setLoadData(true);
    axios
      .get(process.env.REACT_APP_BITCOIN_SERVICE + "/order/book?type=buy")
      .then((response) => handleResponse(response.data.orders))
      .catch((exception) => console.error(exception))
      .finally(() => setLoadData(false));
  };

  if (Object.keys(data).length === 0 && socketActive === false) {
    loadData();
  }

  const socket = () => {
    const websocket = io("https://ws-mig.bitcoin.de:443/market", {
      path: "/socket.io/1",
    });
    websocket.on("connect", function () {
      setSocketActive(true);
    });
    websocket.on("remove_order", function (order) {
      removeOrder(order);
    });
    websocket.on("add_order", function (order) {
      addOrder(order);
    });

    websocket.on("disconnect", function () {
      setSocketActive(false);
    });
  };

  if (socketActive === false && Object.keys(data).length !== 0) {
    socket();
  }
}, [data, socketActive]);

return (
  <Table
    tableHeaderColor="info"
    tableHead={tableHead}
    tableData={data}
    type="buy"
  />
);

有谁知道为什么在通过套接字进行更新时只添加数据中的一个元素,而在每次下一次调用时都被覆盖?

问题

原因是套接字处理程序正在使用第一个渲染器中的状态设置器。

addOrder 为例,您在特定数据值的上下文中创建该函数,当您调用 setData({...data 时,它将始终使用数据的初始状态。 (要了解为什么请参阅来自 facebook 的 React 开发人员 Dan Abramov 的 How do JavaScript closures work? and also A Complete Guide to useEffect

解决方案

您可以改为使用功能更新语法,让您将函数传递给 setData:

setData( data => ({...data,

这确保始终使用最后存储的值。

查看 useState 上的 React 文档 Functional updates