Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does this React code with an anonymous closure do for validateFormat?

I am looking at the source for React 16.4.2 and noticed something that is a bit unfamiliar to me and was wondering how it works. Here is the code:

var validateFormat = function validateFormat(format) {};

{
  validateFormat = function validateFormat(format) {
    if (format === undefined) {
      throw new Error('invariant requires an error message argument');
    }
  };
}

As you can see, there is a variable being declared called validaeFormat and it is being assigned a function as its' value. That makes sense to me. However, immediately after this line you can see that the variable is being reassigned to a function with the same name but different logic within its closure.

The part that confuses me is the additional un-named closure around the re-assignment. It seems to be a common paradigm in the source code for React.

What is the purpose of the extra braces? How does that behave in run-time?

like image 766
Moose Avatar asked Aug 06 '18 18:08

Moose


People also ask

What does React StrictMode do?

StrictMode is a tool for highlighting potential problems in an application. Like Fragment , StrictMode does not render any visible UI. It activates additional checks and warnings for its descendants. Note: Strict mode checks are run in development mode only; they do not impact the production build.

How do you modularize code in React?

React code can easily be modularized by using the component structure. The approach is to define each component into different files. With each component separated into different files, all we have to do is figure out how to access the code defined in one file within another file.

How do I stop execution in React?

To stop this from running, in the command prompt, type CTRL-C. You will get the prompt to Terminate batch job: Type Y and the app will stop running: You can now run npm start again if you want to relaunch the app.

What is code splitting React?

Code-Splitting is a feature supported by bundlers like Webpack, Rollup and Browserify (via factor-bundle) which can create multiple bundles that can be dynamically loaded at runtime.


1 Answers

It seems you are looking at the development version of the React build.

The source is here: https://github.com/facebook/react/blob/aeda7b745d9c080150704feb20ea576238a1b9a1/packages/shared/invariant.js

The code you found actually looks like this before react.development.js is transpiled. If you're not familiar with transpilation, have a quick read about it here but it's typically done in order to use language features that might not yet be supported in older browsers (like let and the arrow-function syntax).

let validateFormat = () => {};

if (__DEV__) {
  validateFormat = function(format) {
    if (format === undefined) {
      throw new Error('invariant requires an error message argument');
    }
  };
}

export default function invariant(condition, format, a, b, c, d, e, f) {
  validateFormat(format);

  if (!condition) {
    let error;
    if (format === undefined) {
      error = new Error(
        'Minified exception occurred; use the non-minified dev environment ' +
          'for the full error message and additional helpful warnings.',
      );
    } else {
      const args = [a, b, c, d, e, f];
      let argIndex = 0;
      error = new Error(
        format.replace(/%s/g, function() {
          return args[argIndex++];
        }),
      );
      error.name = 'Invariant Violation';
    }

    error.framesToPop = 1; // we don't care about invariant's own frame
    throw error;
  }
}

Notice the if (__DEV__) bit? __DEV__ is a global that is typically set to true or false depending on what kind of build they're running, so in the development build this code is going to look like

let validateFormat = () => {};

if (true) {
  validateFormat = function(format) {
    if (format === undefined) {
      throw new Error('invariant requires an error message argument');
    }
  };
}

Now, when that build is optimised, the optimizer will detect that this if check is completely superfluous as it always evaluates to true so it just removes it. It's anyone's guess why it decided to keep the { } block but it could be in order to not accidentally introduce scoping errors.

Now take a look at the production version of the React build. It would be generated with the __DEV__ flag set to false and the optimizer would then realise that it can delete the entire if-clause. The result is that the validateFormat function is a no-op in production while it is doing checks in development. There's lots of these development checks in React that is removed in the production build to save Bytes.

Here's a somewhat prettified version of the code from that variant.js file in the production version of React.

O = function(a, b, f, d, c, k, h, g) {
    if (!a) {
        if (void 0 === b) a = Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");
        else {
            var e = [f, d, c, k, h, g],
                l = 0;
            a = Error(b.replace(/%s/g, function() {
                return e[l++]
            }));
            a.name = "Invariant Violation"
        }
        a.framesToPop = 1;
        throw a;
    }
},

The if(!a) check if actually the if (!condition) check from the original source code (the variable names have been minified to save even more Bytes). The call to validateFormat() that you can see in the source is gone since the entire function is just a no-op because it was never reassigned in the now removed if (__DEV__) block.

This strategy allows React to print helpful error messages and warnings when running in development mode while skipping them in production mode to save on network traffic and because the errors/warnings are of no value to the users.

So, that's it really. I hope that clarifies things a bit and that I didn't confuse you even further. What you found was basically just leftovers from a minification process that ran during the build-step.

like image 119
ivarni Avatar answered Sep 18 '22 15:09

ivarni