slorber / use-async-setState

Permits to await setState()

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

use-async-setState

NPM Build Status

setState returned by useState does not take a callback anymore, but this is sometimes convenient to chain setState calls one after the other.

import { useAsyncSetState } from "use-async-setState";

const Comp = () => {
  const [state,setStateAsync] = useAsyncSetState({ counter: 0 });
  
  const incrementAsync = async () => {
    await setStateAsync(s => ({...s, counter: s.counter+1}));
    await setStateAsync(s => ({...s, counter: s.counter+1}));
    await setStateAsync(s => ({...s, counter: s.counter+1}));
  }
  
  return <div>...</div> 
}   

Reading your own writes in async closures

Warning: this applies if you use closures + setState in the non-functional way (setState(newState) instead of setState(s => s)). You'd rather always use the functional form when possible.

import { useAsyncSetState, useGetState } from "use-async-setState";

const Comp = () => {
  const [state,setStateAsync] = useAsyncSetState({ counter: 0 });
  
  const incrementTwiceAndSubmit = async () => {
    await setStateAsync({...state, counter: state.counter + 1});
    await setStateAsync({...state, counter: state.counter + 1});
    await setStateAsync({...state, counter: state.counter + 1});
  }
  
  return <div>...</div> 
}   

The following won't work fine. In this case, the state variable has been captured by the closure.

It's value is 0 and you are basically doing await setStateAsync({...state: counter: 0 + 1}); 3 times: at the end the counter value is 1.

If you need to use the non-functional setState (which I don't recommend for async stuff), you can use the useGetState helper to get access to the latest state inside your closure:

import { useAsyncSetState, useGetState } from "use-async-setState";

const Comp = () => {
  const [state,setStateAsync] = useAsyncSetState({ counter: 0 });
  const getState = useGetState(state);
  
  const incrementTwiceAndSubmit = async () => {
    await setStateAsync({...getState(), counter: getState().counter + 1});
    await setStateAsync({...getState(), counter: getState().counter + 1});
    await setStateAsync({...getState(), counter: getState().counter + 1});
  }
  
  return <div>...</div> 
}   

Actually, it's exactly the same as when using a classes: you would read the state by using this.state, where this acts somehow as a mutable state ref to access the latest state.

License

MIT

Hire a freelance expert

Looking for a React/ReactNative freelance expert with more than 5 years production experience? Contact me from my website or with Twitter.

About

Permits to await setState()


Languages

Language:TypeScript 93.3%Language:HTML 6.7%