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!');
}
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!'});
}
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) {
// ...
}
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) {
// ...
}
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';
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,
);
}
If you want code-to-code comparison, let me know 👇
P.S. Follow me on Twitter for more content like this!
Top comments (3)
So this opens a brand new way of creating components, like a file may contain different
functions which in turn encapsulate the different component's structures and abiding behaviors. At last all can be called upon by a main function. Can I say this will help in micro-dividing the functions( components ) without wrapping each of its body part in a separate react bracket? Am I right? Also, it would help in avoiding to write the imports for just buttons. I'm eager to know what else can be done?
I don't fully understand what you mean.
Shift from
createElement()
tojsx()
doesn't provide new functionality yet. It just gives the ability to write jsx without React in scope.What is react bracket?
Okay! I got it all wrong. Sorry for that.
Now I read it twice and correctly.