1. 9
  1. 4

    React really is an encoding of incremental computation into JS, and useRef is its implementation of mutation. Maybe it’d be easier to explain React by comparing it to a spreadsheet, where the results are recomputed only when its dependencies change.

    1. 1

      That’s fair. And refs are a way of controlling when certain values are viewed as “changed” or not.

    2. 2

      thank you for posting this. I have been using react for about 5 years, and did not appreciate this. I only used refs for I needed access, directly, to dom elements.

      1. 1

        I think of refs as immutable references to mutable values. Someone else pointed out another way of viewing them, that may be more intuitive to understand: refs are like instance variables on a class.

        These are two very good ways of looking at it. However, the example proposed is more complicated than it needs to be, and it doesn’t need a ref. Contrast with:

        import { useEffect } from 'react';
        function useMyCustomHook(callback) {
          useEffect(() => {
            callback();
          }, []);
        }
        

        Whenever anything in the dependency list (if any) will change, callback will contain its latest value via the magic of plain JavaScript. The only thing that differs is, if you use the exhaustive-deps eslint rule, it’s going to lament not including callback in the deps list, but IMO that rule needs to be taken with a grain of common-sense.

        I think the article would benefit from an example when the ref is necessary, e.g. when the effect is run asynchronously, or multiple times. But even then, we can get rid of the first useEffect() and just update callbackRef.current inline.