skip to Main Content

I just try to create a React Native library, and currently I’ve a use case that my function can be declared using

  • const show = useMyHook()

or

  • const {show, hide} = useMyHook()

useMyHook.js

const useMyHook = () => {
  const MyCTX = useContext(MyContext);
  if (!MyCTX) {
    throw new Error('useMyHook must be defined.');
  }
  // how do i conditionally return
  // return {show: MyCTX.show, hide:MyCTX.hide}
  // and
  // return MyCTX.show
  return MyCTX.show;
};

export default useMyHook;

what should i do to make useMyHook() accept both of them? or is it not possible?

the main reason why I want useMyHook() can accept both of them is, so dev can naming anything into variable when they only want to call show() as a function like so:

const showMyHookInBannerHomepage = useMyHook()

i think it’s more simple rather than

const {show:showMyHookInBannerHomepage} = useMyHook()

2

Answers


  1. One way which I can think of is to make the hook work for both use cases by returning a function with properties attached to it. Something like:

    function useMyHook() {
      const MyCTX = useContext(MyContext);
      if (!MyCTX) {
        throw new Error("useMyHook must be defined.");
      }
    
      // Create a function that calls MyCTX.show
      const callableFunction = function() {
        return MyCTX.show();
      };
    
      // Attach show and hide properties to the function
      callableFunction.show = MyCTX.show;
      callableFunction.hide = MyCTX.hide;
    
      return callableFunction;
    }
    
    // Usage 
    // Either
    const { show, hide } = useMyHook();
    // Or
    const show = useMyHook();
    

    SAMPLE DEMO


    Alternative Approach

    Another way would require you to use a parameter(if you like to change the signature of your hook) to your hook based on which you can conditionally use them. A sample would look like:

    const useMyHook = (returnObject = false) => {
      const MyCTX = useContext(MyContext);
      if (!MyCTX) {
        throw new Error('useMyHook must be defined.');
      }
      // Conditionally return based on the `returnObject` parameter
      if (returnObject) {
        return {show: MyCTX.show, hide: MyCTX.hide};
      } else {
        return MyCTX.show;
      }
    };
    
    // To use
    
    // Just get the `show` function
    const show = useMyHook();
    
    // Get both `show` and `hide` functions in an object
    const {show, hide} = useMyHook(true);
    

    SIDENOTE:

    1. You can also leverage Proxy API to achieve your requirement. Although, there might be some performance bottleneck to it(in case you’re ready to sacrifice some) since it intercepts and redefines operations on objects.
    2. If there is not a very specific need I would stick to the destructure approach and leave it on devs(using the hook) as what they want to destructure from the hook.
    Login or Signup to reply.
  2. Note that destructuring assignment will happily ignore any properties that aren’t mentioned; so even without doing anything special, any callers that don’t need hide can simply write:

    const {show} = useMyHook();
    

    That’s what I’d recommend unless you have a particularly strong reason to do something different. I say this not because the above is trivial to implement (though it is), but because it’s trivial to understand. Any other approach makes it hard to describe what useMyHook returns.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search