Quantcast
Channel: Active questions tagged react-native+typescript - Stack Overflow
Viewing all articles
Browse latest Browse all 6287

Poll and update state UNLESS a specific prop updates

$
0
0

I'm building a React Native application that is polling for wallet balances every 6 seconds. I've setup a timer which I am using to 1) call ONCE initially for balance (ie. not wait 6 seconds for the interval in my timer to run) and 2) poll as normal after that.

The problem I'm having is the user can change the state while the polling is happening but because the interval is already running what happens is the user updates the state then the polling code overwrites it.

For example given assetBalances of:

{ lorem: { balance: 100 } }

If the user were to change the wallet name from "lorem" to "ipsum" I'd momentarily be left with assetBalances of:

{ ipsum: { balance: 100 } }

Which would then quickly become the following when the poll has ran. (The reason it adds to the object is because I spread with ... as you can see in network-scan.ts):

{ lorem: { balance: 100 }, ipsum: { balance: 100 } }

I've tried using a custom usePrevious hook which compares the last prop to current prop and then I conditionally call the setAsyncValue in network-scan.ts but that didn't work.

I need a way to CANCEL the running timer.start instance if x prop changes (x being assetBalances in my first case).

On a side note I'm also having an issue where for some reason when there's lots of state changes the timer gets called multiple times which causes loads of intervals to run parallelly, which I don't understand because I'm calling timer.stop() at the start of every useEffect re-render - why?

If anyone has any ideas as to how I can solve these issues I'd really appreciate it! Or is there a much easier way to do what I'm trying to do? Here's some code for context:

timer.ts

const timer = {  running: false,  timeout: false,  cb: function () {},  start: function (cb: any, iv: number, cbAtEnd?: any) {    const elm = this;    clearInterval(this.timeout);    this.running = true;    if (cb) this.cb = cb;    this.timeout = setTimeout(function () {      elm.execute(elm);      if (cbAtEnd) cbAtEnd();    }, iv);  },  execute: function (e: any) {    if (!e.running) return false;    e.cb();    e.start();  },  stop: function () {    this.running = false;  },};

polling.ts

export default function useNetworkPolling(): void {  const {    state: {      wallets,      userToken,      assetBalances,      selectedWallet,      connectedNetwork,      networkPollingInterval,      networkSpecificTokens,    },    setAsyncValue,  } = useContext(LocalContext);  const intervalTime = networkPollingInterval // default 6s  const address = useGetWalletAddress(selectedWallet);  useEffect(() => {    function scan() {      console.log(`Scan now! - (Interval time is: ${intervalTime}ms) [from useNetworkPolling]`);      const filteredTokens = getTokensFilteredByTrackedStatus(        connectedNetwork,        networkSpecificTokens      );      const allTokens = CORE_TOKENS.concat(filteredTokens);      handleNetworkScan(        allTokens,        JSON.parse(assetBalances),        address,        setAsyncValue,        connectedNetwork,        selectedWallet      );      console.log(JSON.stringify(JSON.parse(assetBalances), null, 2));    }    timer.stop(); // Make sure the previous one is stopped so two never run at the same time    if (userToken && JSON.parse(wallets).length) {      // Start off with an immediate one-off call      timer.start(scan, 1, () => {        timer.stop(); // Pass a callback into the start function which stops the first timer        timer.start(scan, intervalTime); // Start polling with the interval      });    }  }, [    address,    userToken,    networkPollingInterval,    wallets,    connectedNetwork,    networkSpecificTokens,    assetBalances,    selectedWallet,  ]);}

network-scan.ts

export default async function handleNetworkScan(  coreAndTrackedTokens: Token[],  assetBalances: any,  address: string,  setAsyncValue: (key: string, value: string) => Promise<void>,  connectedNetwork: string,  selectedWallet: string) {  let updatedBalances = assetBalances[selectedWallet];  for (const token of coreAndTrackedTokens) {    try {      // Redacted logic that updates updatedBalances if success...    } catch (e) {      // Redacted logic that updates updatedBalances if error...    }  }  setAsyncValue('assetBalances',    JSON.stringify({ ...assetBalances, [selectedWallet]: updatedBalances })  );}

Viewing all articles
Browse latest Browse all 6287

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>