Home > other >  Best practice for useEffect for a update action you want to use in multiple places in code
Best practice for useEffect for a update action you want to use in multiple places in code

Time:03-15

Let's say I have a useEffect like this:

useEffect(() => {
  getMarket(web3, marketaddress, marketindex).then(setMarket);
}, [web3Ref, marketaddress, marketindex]);

This works OK, but now say I need to have this line in a few places (because various async actions require a refresh of the market:

  getMarket(web3, marketaddress, marketindex).then(setMarket);

Are there any better options than what I can think of:

  1. Copy and paste getMarket(web3, marketaddress, marketindex).then(setMarket); in each place.

  2. Declare a function, but because of the react-hooks/exhaustive-deps I will get a lint error unless the function is a static outside of the component, in which case it would need to take setMarket as an argument, which seems silly.

  3. Use an additional piece of pseudo-state to track changes, e.g. a number called version. Increment it whenever I want to refresh and then add this as a dependency to the useEffect above. Something like:

    useEffect(() => {
      getMarket(web3, marketaddress, marketindex).then(setMarket);
    }, [web3Ref, marketaddress, marketindex, changeIndex]);

Is there a better/alternative way than anything I have described?

CodePudding user response:

#3. People expect useEffect() to alter state so this is the ideal place for your code.

You can introduce a const [marketIsDirty, setMarketIsDirty] = useState(true) and if a user action or external condition should cause the market to be updated, call setMarketIsDirty(true) to trigger the state refresh.

call inside useEffect, setMarketIsDirty(false) once you've updated the market.

Also, do not update the market when marketIsDirty is false to avoid infinite loops.

Better, introduce a 'marketState' state with an enumeration of DIRTY, UPDATING, SUCCESS, ERROR so you can manage the UI in concert with the state changes.

CodePudding user response:

I would recommend a custom hook which you can import to all your components, a custom hook can use its own state so there's no need to send the setState function.

It would look something like this:

//useMarket.js

const useMarket = (web3, marketaddress, marketindex)=>{

    const [market, setMarket] = useState();

    useEffect(() => {
        getMarket(web3, marketaddress, marketindex).then(setMarket);
    }, [web3Ref, marketaddress, marketindex]);

    return market;
}

export default useMarket;

That's it based on the info you provided, now I'll give some advice which comes to mind but may be not so useful for you.

  • I usually use named parameters in hooks so I can edit them later withou having to change every place I use them, so the declaration would be like const useMarket = ({web3, marketaddress, marketindex})
  • It seems to me that web3 is the the js library to communicate with a blockchain, so you may find a better way to get inside the hook so you don't need to send it every time you call it.
  • If you call this in many components that require the same info, I would suggest to use come kind of cache inside you hook to prevent several api calls for the same information
  • You can change what you return to be an object if you want to expose something more than just the market state. Something like the setter, or the cache control methods if you happen to implement it.
  • You're actual code is missing error handling, so you could return another variable with a "state" of the hook, there you may tell the ui if it's loading or if there was an error getting the data
  • Related