收到新对象后,对useState中的对象数组进行更新或添加

时间:2020-04-11 02:33:13

标签: reactjs typescript

有时会从WebSocket收到newItem,并通过saveNewItem保存到useState

然后按预期开始useEffect块。

更新。如果closeArray中有一个与openTime相同的newItem对象,我想用closeArray替换newItem中的对象,因为它将一个新的close

添加。如果closeArray中没有打开时间与newItem相同的对象,我想将新项目推送到数组中。

删除。最后,如果数组的长度超过39个对象,我想删除第一项。

如果我将closeArray添加到useEffect依赖项数组中,我将创建一个讨厌的循环,如果我不添加它,closeArray将不会更新

我希望usEffect仅在newItem更改时才触发,而不是closeArray更改时才触发,但我仍想获取{{1 }}

closeArray

如果我确实将useEffect添加到interface CloseInterface { openTime: number; closeTime: number; close: number; } function App() { const [newItem, saveNewItem] = useState<CloseInterface>(); const [closeArray, saveCloseArray] = useState<CloseInterface[]>([]); useEffect(() => { if (newItem) { let found = false; let arr = []; for (let i = 0; i < closeArray.length; i++) { if (closeArray[i].openTime === newItem.openTime) { found = true; arr.push(newItem); } else { arr.push(closeArray[i]); } } if (found === false) { arr.push(newItem) } if (arr.length === 39) arr.shift(); saveCloseArray(arr); } }, [newItem]); // <--- I need to add closeArray but it will make a yucky loop 依赖数组中,则会出现错误...

closeArray

如果我不将useEffect添加到index.js:1 Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render. in App (at src/index.tsx:9) in StrictMode (at src/index.tsx:8) 依赖数组中,则会出现此错误...

closeArray

第二个useEffect块获取React Hook useEffect has a missing dependency: 'closeArray'. Either include it or remove the dependency array react-hooks/exhaustive-deps 的初始数据,并侦听WebSocket,该WebSocket在到达useEffect时对其进行更新。

closeArray

3 个答案:

答案 0 :(得分:1)

为了更好地编写代码,您可以使用状态更新程序的回调方法,这样,即使您不将closeArray传递给useEffect,它也会在useEffect的每次运行中积累更新的值

function App() {
  const [newItem, saveNewItem] = useState<CloseInterface>();
  const [closeArray, saveCloseArray] = useState<CloseInterface[]>([]);

  useEffect(() => {
    if (newItem) {
      let found = false;

      saveCloseArray(prevCloseArray => {
         let arr = [];
         for (let i = 0; i < prevCloseArray.length; i++) {
            if (prevCloseArray[i].openTime === newItem.openTime) {
              found = true;
              arr.push(newItem);
            } else {
              arr.push(prevCloseArray[i]);
            }
          }
          if (found === false) {
            arr.push(newItem)
          }
          if (arr.length === 39) arr.shift();
          return arr;
      })
    }
  }, [newItem]); 

答案 1 :(得分:0)

您要使用useCallback来保存带有更新项的新数组,如下所示:

const [closeArray, saveCloseArray] = useState<CloseInterface[]>([]);
const updateEntry = useCallback(newItem => {
  saveCloseArray(oldCloseArray => oldCloseArray.reduce((acc, item) => {
    acc.push(item.openTime === newItem.openTime ? newItem : item);
    return acc;
  }, []));
}, []);

然后将回调函数应用于按钮或div或正在生成的任何组件(例如EG)

return (
  [1, 2, 3, 4, 5].map(item => <button key={`${item}`} onClick={() => updateEntry(item)}>Click me</button>)
);

答案 2 :(得分:0)

如果您拥有newItem的唯一原因是更新closeArray,则可以考虑将该功能移至利用WebSocket的useEffect中。如果除了更新newItem之外还需要执行其他操作,例如显示警报或弹出窗口,仍然可以使用closeArray。这就是我的意思:

interface CloseInterface {
    openTime: number;
    closeTime: number;
    close: number;
}

function App() {
    const [newItem, saveNewItem] = useState<CloseInterface>();
    const [closeArray, saveCloseArray] = useState<CloseInterface[]>([]);

    useEffect(() => {
        // Do something when newItem changes, e.g. show alert
        if (newItem) {

        }
    }, [newItem]);

    useEffect(() => {
        // Work with the new item
        const precessNewItem = (item = {}) => {
            let found = false;
            let arr = [];

            for (let i = 0; i < closeArray.length; i++) {
                if (closeArray[i].openTime === item.openTime) {
                    found = true;
                    arr.push(item);
                } else {
                    arr.push(closeArray[i]);
                }
            }

            if (found === false) {
                arr.push(item)
            }

            if (arr.length === 39) arr.shift();

            saveCloseArray(arr);

            // save new item 
            saveNewItem(item);
        };

        const getDetails = async () => {
            const params = new window.URLSearchParams({
                symbol: symbol.toUpperCase(),
                interval
            });

            const url = `https://api.binance.com/api/v3/klines?${params}&limit=39`;
            const response = await fetch(url, { method: "GET" });
            const data = await response.json();

            if (data) {
                const arrayLength = data.length;
                let newcloseArray = [];
                for (var i = 0; i < arrayLength; i++) {
                    const openTime = data[i][0];
                    const closeTime = data[i][6];
                    const close = data[i][4];
                    newcloseArray.push({ openTime, closeTime, close });
                }

                saveCloseArray(newcloseArray);
                const ws = new WebSocket("wss://stream.binance.com:9443/ws");

                ws.onopen = () =>
                    ws.send(
                        JSON.stringify({
                            method: "SUBSCRIBE",
                            params: [`${symbol}@kline_${interval}`],
                            id: 1
                        })
                    );

                ws.onmessage = e => {
                    const data = JSON.parse(e.data);
                    const value = data.k;

                    if (value) {
                        const openTime = value.t;
                        const closeTime = value.T;
                        const close = value.c;

                        // process new item
                        processNewItem({ openTime, closeTime, close });
                    }
                };
            }
        };
        getDetails();
    }, [symbol, interval, closeArray]); // add closeArray here
 }