Hook Return Types

The "3, 2, 1 Rule"

We have three options for returning a hook in React, Vue, or Angular. We can choose amongst:

  • A single variable
  • Destructed Array
  • Destructed object or object variable

We just need to keep the "3, 2, 1 rule" in mind what we should return.

If we are returning just a single state object, then only the variable is required. There is no need to return it inside an array or object.

            
        export default useMyHook(): string {
            const partA = useState<string>();

            // Other methods and lifecycle methods here.

            return partA;
        };

        const myHookObject = useMyHook();
            
        

For two or three variables, an array is the best choice.

            
        export default useMyHook(): [string, number] {
            const partA = useState<string>();
            const partB = useState<number>();

            // Other methods and lifecycle methods here.

            return [partA, partB];
        };

        const [partA, partB] = useMyHook();
            
        

Finally, with three variables, we can still return an array; however anything that returns four or more variables should always be an object.

            
        export default useMyHook(): { partA: string, partB: number, partC: Date } {
            // Ref's and other lifecycle methods here.

            return { partA, partB, partC }
        };

        const myHookObject = useMyHook();
            
        

Sometimes if the object is large enough it may be a good idea to define an interface to avoid a confusing return type.

            
        export default interface IMyHook {
          partA: string;
          partB: number;
          partC: Date;
          partD: boolean;
        }

        export default function useMyHook(): IMyHook {
          // Ref's and other lifecycle methods here.

          return { partA, partB, partC, partD };
        }
            
        

Vue is Complicated

Because of how Vue's reactivity works, we need to return naked Ref's from our hooks. While the following is possible:

            
        const myHook = useMyHook();

        const [partA, partB] = useMyHook();

        const { partA, partB, partC } = useMyHook();
            
        

The following is not allowed by default.

            
        export default useMyHook(): { partA: string, partB: number, partC: Date } {
            // Ref's and other lifecycle methods here.

            return { partA, partB, partC }
        };

        const myHookObject = useMyHook();
            
        

Returning an object variable will cause the hook to lose its reactivity. We need to destructure the object like so.

            
        const { partA, partB, partC } = useMyHook();
            
        

There is a Way

You can get around this by wrapping your hook in a "reactive" function that will restore the reactivity to your hook.

            
        const myHookObject = reactive(useMyHook());
            
        

Yet, I do not recommend doing this, as it may be confusing to other developers when and where this is needed.

Conclusion

If you stick to the "3, 2, 1 Rule," you will provide your fellow developers with a consistent interface to interact with hooks. Just remember to keep your Vue hooks destructured.