vikram sah
vikram sah

Reputation: 91

State JS object not persistent upon setState

I have a state which looks like this.

let coinlist = {
    BTC:0,
    ETH:0,
    USDT:0,
    XRP:0,
    ADA:0,
    SOL:0,
    AVAX:0,
    DOT:0,
    DOGE:0,
    UST:0,
    SHIB:0,
    MATIC:0,
    WBTC:0,
    CRO:0,
    DAI:0,
    LTC:0,
    ATOM:0,
    LINK:0,
    UNI:0,
    BCH:0,
    XLM:0
}
  const [currencies, setCurrencies] = useState(coinlist);

I am using a websocket which provides the real time price values of these currencies. My onmessage looks like this.

 useEffect(() => {
  // ...code to set up & configure the websocket

ws.current.onmessage = (e) => {
      let data = JSON.parse(e.data);
      console.log(data)
      if (data.type !== "ticker") {
        return;
      }
      setCurrencies({
          ...currencies,
          [data.product_id.replace("-USD","")]:data.price
      })
    };
  }, []);

Now, upon receiving every new price for any of the currencies from the ws, the setState only updates the particular currency, i.e the values are not persistent accross the setStates. The console.log looks something like this.

ADA: 0
ATOM: 0
AVAX: 0
BCH: 0
BTC: 0
CRO: 0
DAI: 0
DOGE: 0
DOT: 0
ETH: 0
LINK: 0
LTC: "125.07"
MATIC: 0
SHIB: 0
SOL: 0
UNI: 0
USDT: 0
UST: 0
WBTC: 0
XLM: 0
XRP: 0

and the next message looks like this.

ADA: 0
ATOM: 0
AVAX: 0
BCH: 0
BTC: "43935.89"
CRO: 0
DAI: 0
DOGE: 0
DOT: 0
ETH: 0
LINK: 0
LTC: 0
MATIC: 0
SHIB: 0
SOL: 0
UNI: 0
USDT: 0
UST: 0
WBTC: 0
XLM: 0
XRP: 0

What i am expecting is something like this.

BTC: "43935.89"
SOL: "10.56"
UNI: "277"
USDT: "25"
UST: "105"
WBTC: "200"
XLM: "100.23"
XRP: "0.5"

Am i using the setCurrencies properly??

Upvotes: 1

Views: 43

Answers (1)

Drew Reese
Drew Reese

Reputation: 203146

Issue is a stale closure over the currencies state. Use a functional state update to correctly update from the previous state instead of the initial state closed over in callback scope.

Example:

useEffect(() => {
  // ...code to set up & configure the websocket

  ws.current.onmessage = (e) => {
    const data = JSON.parse(e.data);
    console.log(data);

    if (data.type !== "ticker") {
      return;
    }

    setCurrencies(currencies => ({ // <-- previous state
      ...currencies,               // <-- shallow copy
      [data.product_id.replace("-USD","")]: data.price
    }));
  };

  // Don't forget code to clean up socket connections/subscriptions!!
}, []);

Upvotes: 3

Related Questions