This content originally appeared on DEV Community and was authored by Nick | React tinkerer ⚛️
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 more content like this!
Why does React source code have block statements without condition or loop?
🧵👇18:01 PM - 22 Jan 2022
This content originally appeared on DEV Community and was authored by Nick | React tinkerer ⚛️
Nick | React tinkerer ⚛️ | Sciencx (2022-02-03T19:48:50+00:00) JSX without importing React. Retrieved from https://www.scien.cx/2022/02/03/jsx-without-importing-react/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.