如何根据 id 是否与 websocket 对象的 id 匹配有条件地呈现列表项

How to conditionally render a list item based on if id matches a websocket object's id

我的目标是使用页面上的按钮打开 websocket 连接,订阅代码提要,然后根据列表项的 ID 更新每个列表项的价格。目前我有一个列表,它通过初始 API 调用的响应进行映射,并将每个对象的 ID 保存到一个数组,该数组又用于为每个 ID 构建一个 <li>。这将创建 96 个列表项。我还通过每个 <li>.

中的 <p> 元素获得了实时更新的价格

我在将匹配行 ID 的价格定位到传入数据对象的 ID 时遇到问题,因此只有匹配行在获得匹配项时才重新呈现。下面是我的代码:

ProductRow.js

import React from 'react';

export default function ProductRow(props) {
    return <li key={props.id}><p>{ props.id }</p><p>{props.price}</p></li>;
}

WatchList.js

import React, { useState, useEffect, useRef } from "react";
import { Button } from 'react-bootstrap';
import ProductRow from "./ProductRow";

export default function WatchList() {
  const [currencies, setcurrencies] = useState([]);
  const product_ids = currencies.map((cur) => cur.id);
  const [price, setprice] = useState("0.00");
  const [isToggle, setToggle] = useState();
  const ws = useRef(null);

  let first = useRef(false);
  const url = "https://api.pro.coinbase.com";

  useEffect(() => {
    ws.current = new WebSocket("wss://ws-feed.pro.coinbase.com");

    let pairs = [];

    const apiCall = async () => {
      await fetch(url + "/products")
        .then((res) => res.json())
        .then((data) => (pairs = data));
      
      let filtered = pairs.filter((pair) => {
        if (pair.quote_currency === "USD") {
          return pair;
        }
      });

      filtered = filtered.sort((a, b) => {
        if (a.base_currency < b.base_currency) {
          return -1;
        }
        if (a.base_currency > b.base_currency) {
          return 1;
        }
        return 0;
      });

      
      setcurrencies(filtered);
      first.current = true;
    };
    apiCall();
  }, []);
  

  useEffect(() => {
    ws.current.onmessage = (e) => {
      if (!first.current) {
      
        return;
      }
      let data = JSON.parse(e.data);
      if (data.type !== "ticker") {
        return;
      }
      
      setprice(data.price);
      
      console.log(data.product_id, price);
    };
    
  }, [price]);
  
  const handleToggleClick = (e) => {
    if (!isToggle) {
      let msg = {
        type: "subscribe",
        product_ids: product_ids,
        channels: ["ticker"]
      };
      let jsonMsg = JSON.stringify(msg);
      ws.current.send(jsonMsg);
      setToggle(true);
      console.log('Toggled On');
    }
    else {
      let unsubMsg = {
        type: "unsubscribe",
        product_ids: product_ids,
        channels: ["ticker"]
      };
      let unsub = JSON.stringify(unsubMsg);
  
      ws.current.send(unsub);
      setToggle(false);
      console.log('Toggled Off');
    }
  };
  return (
    <div className="container">
      <Button onClick={handleToggleClick}><p className="mb-0">Toggle</p></Button>
    <ul>
    {currencies.map((cur) => {
      return <ProductRow id={cur.id} price={price}></ProductRow>
    })}
    </ul>
    </div>
  );
}

App.js

import React from "react";
import WatchList from "./components/Watchlist";
import "./scss/App.scss";

export default class App extends React.Component {
  render() {
    return (
          <WatchList></WatchList>
    )
  }
}
  1. price 状态初始化为空对象,即 {}。我们将在从 websocket
  2. 获得响应时通过 product_id 参考价格值
// Initialize to empty object
const [price, setprice] = useState({});
...

// Refer and update/add the price by the product_id 
useEffect(() => {
  ws.current.onmessage = (e) => {
    if (!first.current) {
      return;
    }
    let data = JSON.parse(e.data);
    if (data.type !== "ticker") {
      return;
    }
    // setprice(data.price)
    setprice(prev => ({ ...prev, [data.product_id]: data.price}));
    console.log(data.product_id, price);
  };
}, [price]);
  1. 将您的 ProductRow 渲染为
<ul>
   {currencies.map((cur) => {
     return <ProductRow key={cur.id} id={cur.id} price={price[cur.id]}></ProductRow>
   })}
</ul>

您无需管理任何类型的排序或搜索产品的相关价格。