0

I receive data from a websocket in my react app. The data holds prices for stock symbols:

{symbol: "aapl", price: 150}

I want to save the price for each stock in an individual Atom, where the key is the symbol and data is the price. There could be thousands of Atoms, each corresponding to a unique stock.

Is there a way I can dynamically create a new Atom, set (or update) its data, and read the Atom state somewhere else in the app? Essentially, a dictionary of Atoms, where the key is the stock symbol and state is stock price.


EDIT: This should provide more clarity on my issue: https://github.com/facebookexperimental/Recoil/issues/1406

Context: I use a websocket to stream stock prices. The realtime data comes in bundles every 0.25 seconds, containing hundreds of stock prices in the following format: {symbol:"aapl", price:150}

Issue: I need to create an independent state for each of the stocks, updating their prices as the data comes in. It also needs to be performant, as sometimes I receive 8000 stocks per second. The stock prices will be used in components throughout the app, some of which are not connected to the parent websocket component at all.

As far as I know there are two options:

Create one big Atom containing the whole websocket message, then subscribe to this big block of state

-This would cause all subscribed components to update at once, no?

Generate an Atom for each unique stock, and update the atom when a new stock price is received

-I do not know how to do this in Recoil

Essentially it comes down to a key-value pair where the key is stock symbol and value is an Atom storing the price state. Is there a way I can create such a structure and allow independent components to subscribe to these Atoms? E.g. a component "X" subscribes to the state corresponding to stock "AAPL"... Any ideas?

  • Do you mean a global state? Like when the stocks change (added, removed, modified, etc), your UI will have some changes as well? – Matthew Kwong Nov 10 '21 at 05:51
  • @MatthewKwong yes but not one big state. I need a state for each stock, which in my case will be thousands. The reason I would prefer many states is so I can refresh one stock without refreshing the others. – Eoin Fitzpatrick Nov 10 '21 at 06:12
  • I think you have misunderstood how the state works, if you have an array state, modifying one element will not necessarily cause all components depending on it to re-render. It is a long story though. – Matthew Kwong Nov 10 '21 at 06:18

2 Answers2

0

Since you are looking for global state management framework/tools. You have a few options.

React Context - If you don't want any 3rd party package

React Redux - Basically the industry standard of React global state management.

MobX - Do the same job with a different methodology. Usually faster than Redux, but is less popular.

Matthew Kwong
  • 2,548
  • 2
  • 11
  • 22
0

Going to answer my own question. Better late than never.

I defined atoms in atoms.js

import { atomFamily } from "recoil";

export const stockAtom = atomFamily({
    key: "symbol",
    default: {},
});

In my setter file (where I want to set the atom values):

import { useRecoilTransaction_UNSTABLE } from "recoil";
import { stockAtom } from "./atoms";
  // ... functional component
  const updateState = useRecoilTransaction_UNSTABLE(
    ({ set }) => (stockObj) => {
      for (const stock of stockObj) {
        // set the atom of stock.sym to the jsondata from the websocket
        set(stockAtom((stock.sym).toLowerCase()), stock);
      }
    },
    []
  );

  // websocket on message
  const _onMessage = (msg) => {
    const data = JSON.parse(msg.data)
    updateState(data)
  }
  // ...

Then in a file I want to consume/get the atoms in:

import { stockAtom } from "./atoms";
import { useRecoilValue } from "recoil";
// passed stock sytmbol as props string
const WatchlistItem = (props) => {
  // consume the stock price of atom with key props.symbol
  const symbolData = useRecoilValue(stockAtom(props.symbol));
  return (<div> symbolData["price"]</div>);
}

I recommend doing error handling with objects/dicts, which I left out for this example