March 26, 2023

Blog @ Munaf Sheikh

Latest news from tech-feeds around the world.

JSX without importing React – DEV Community


React 17 provides support for a new version of the JSX transform.
Simply put, it allows using JSX without having React in scope.

Let’s figure out why it’s possible and how it works.



The previous state of things โฎ๏ธ

Prior to React v17.0.0, JSX transform used React.createElement internally.
There was one minor and one major problem with this approach:
๐Ÿ‘‰ React must be in scope
๐Ÿ‘‰ “Some performance improvements and simplifications” weren’t possible

// Before transpilation
import React from 'react';

const Item = () => {
  return <div>Hello world!</div>;
}

// After transpilation
// React is available in global scope

const Item = () => {
  return React.createElement('div', null, 'Hello world!');
}
Enter fullscreen mode

Exit fullscreen mode



A whole new world โœจ

Starting from React 17, JSX transform use special jsx function internally.
You don’t need to import it. Instead, the transpiler automatically imports it from React package at build time.

// Before transpilation
const Item = () => {
  return <div>Hello world!</div>;
}

// After transpilation
import {jsx as _jsx} from 'react/jsx-runtime'; 

const Item = () => {
  return _jsx('div', {children: 'Hello world!'});
}
Enter fullscreen mode

Exit fullscreen mode



createElement ๐Ÿ†š jsx

These two functions serve the same purpose, but they are different in a few ways.
Let’s take a thorough look at them and examine how it all works under the hood.



API difference

createElement takes three arguments:
๐Ÿ‘‰ element type (tag name, function/class, React.Fragment)
๐Ÿ‘‰ props, passed to the element
๐Ÿ‘‰ children of the element

Only the first argument is mandatory.

/**
* @param type - type of the element
* @param config - props passed to the element
* @param children - children of the element
*/
function createElement(type, config, children) {
  // ...
}
Enter fullscreen mode

Exit fullscreen mode



jsx takes three arguments too, but they aren’t the same.

๐Ÿ‘‰ element type is exactly the same
๐Ÿ‘‰ props, including children and excluding key
๐Ÿ‘‰ key, that you use to create lists of elements

Here only the first argument is mandatory too.

/**
* @param type - type of the element
* @param config - props passed to the element, including children and excluding key
* @param maybeKey - key, that you use to create lists of elements
*/
function jsx(type, config, maybeKey) {
  // ...
}
Enter fullscreen mode

Exit fullscreen mode



Use cases

createElement has two use cases:
๐Ÿ‘‰ manually create elements in your code
๐Ÿ‘‰ transform JSX before React 17

jsx function should only be used by the compiler.
โŒ You must not use it on your own.



Dev mode

createElement internally makes a couple of checks to provide meaningful warnings in development mode.

jsx function instead has two separate versions:
๐Ÿ‘‰ jsx for production mode
๐Ÿ‘‰ jsxDEV for development mode

That’s why jsx is cleaner and shorter than createElement

// react/jsx-dev-runtime.js
export {jsxDEV} from './src/jsx/ReactJSX';

// =======================================

// react/jsx-runtime.js
export {jsx} from './src/jsx/ReactJSX';
Enter fullscreen mode

Exit fullscreen mode



Fundamental similarities

Despite all differences, you need to keep in mind that both functions eventually use ReactElement().
So, the output is almost identical.

export function createElement(type, config, children) {
  // ...

  return ReactElement(
    type,
    key,
    ref,
    self,
    source,
    ReactCurrentOwner.current,
    props,
  );
}

// ====================================================

export function jsx(type, config, maybeKey) {
  // ...

  return ReactElement(
    type,
    key,
    ref,
    undefined, // <- minor difference here
    undefined, // <- and here too
    ReactCurrentOwner.current,
    props,
  );
}
Enter fullscreen mode

Exit fullscreen mode

If you want code-to-code comparison, let me know ๐Ÿ‘‡

P.S. Follow me on Twitter more content like this!





Source link