The near future of how we will use React
A global context named FormContext
const FormContext = createContext(defaultFormContext);
const useForm = () => useContext(FormContext);
function FormProvider({ children }) {
const [data, setData] = useState<FormFields>({
name: createDefaultInputState(),
// ...
});
const updateField = <K>(field: K, value: Partial<FormFields[K]>) => {
setData(prevData => ({
...prevData,
[field]: {
...prevData[field],
...value,
},
}));
};
return (
<FormContext.Provider
value={{
...data,
updateField,
}}
>
{children}
</FormContext.Provider>
);
}
Two controlled form components like this:
const Select = ({
id, label, options, value, onChange,
}) => {
const handleChange = (event) => {
onChange(event.target.value);
};
return (
<div className="select-wrapper">
<label htmlFor="select" className="select-label">
{label}
</label>
<select id={id} value={value || ''} onChange={handleChange}>
{options.map((option) => {
increaseRenderCount('select-option');
return (
<option key={option.value} value={option.value}>
{option.label}
</option>
);
})}
</select>
</div>
);
};
A form component
const Form = () => {
const { name, surname, city, district, address, updateField } = useForm();
// We will keep track of this fn calls just in case:
const filteredDistrictList = getDistrictList(city.value);
return (
<div>
<Input
value={name.value}
onChange={(event) =>
updateField('name', { value: event.currentTarget.value })
}
/>
<Input id="surname" {/* ... */} />
<Select
options={CITY_LIST}
value={city.value}
onChange={(value) => updateField('city', { value: Number(value) })}
/>
<Select options={filteredDistrictList} {/* ... */} />
<Input id="address" {/* ... */} />
</div>
);
}
When the rule does not pass, it means that the compiler has skipped over optimizing that component or hook.
import reactCompiler from 'eslint-plugin-react-compiler'
export default [
{
plugins: {
'react-compiler': reactCompiler,
},
rules: {
'react-compiler/react-compiler': 'warn',
},
},
];
Example compiler lint issue:
We will integrate the React Compiler with Babel.
The React Compiler supports most build tools.
import {
defineReactCompilerLoaderOption,
reactCompilerLoader,
} from "react-compiler-webpack";
module.exports = {
// ...
module: {
rules: [
// Current:
{
test: /\.(js|jsx)$/,
exclude: /node_modules\/.*/,
use: {
loader: "babel-loader",
options: {
presets: [["@babel/preset-env", { targets: "defaults" }]],
},
},
},
// New:
{
test: /\.[mc]?[jt]sx$/i,
exclude: /node_modules/,
use: [
{
loader: reactCompilerLoader,
options: defineReactCompilerLoaderOption({
// React Compiler options goes here
// compilationMode: 'annotation',
}),
},
],
},
],
},
} satisfies WebpackConfiguration;
export const Select = ({
id, options, value, onChange,
}: SelectProps) => {
return (
<select
id={id}
value={value || ""}
onChange={onChange}
>
{options.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
);
};
import { jsx as _jsx } from "react/jsx-runtime";
export const Select = ({ id, options, value, onChange, }) => {
return (
_jsx("select", {
id: id,
value: value || "",
onChange: onChange,
children: options.map(
(option) => (
_jsx("option", {
value: option.value,
children: option.label
}, option.value)
)
)
})
);
};
import { jsx as _jsx } from "react/jsx-runtime";
import { c as _c } from "react/compiler-runtime";
export const Select = t0 => {
const $ = _c(7);
const { id, options, value, onChange } = t0;
const t1 = value || "";
// Auto generated memoization (low level)
let t2;
if ($[0] !== options) {
t2 = options.map(_temp);
$[0] = options;
$[1] = t2;
} else {
t2 = $[1];
}
let t3;
if ($[2] !== id || $[3] !== onChange || $[4] !== t1 || $[5] !== t2) {
t3 = _jsx("select", { id: id, value: t1, onChange: onChange, children: t2 });
$[2] = id;
$[3] = onChange;
$[4] = t1;
$[5] = t2;
$[6] = t3;
} else {
t3 = $[6];
}
return t3;
};
// Function Outlining
function _temp(option) {
return _jsx("option", { value: option.value, children: option.label }, option.value);
}
Directory/path based filter:
{
loader: reactCompilerLoader,
options: defineReactCompilerLoaderOption({
sources: (filename) => {
return filename.indexOf('src/path/to/dir') !== -1;
},
}),
}
"use no memo";
directive:
function SuspiciousComponent() {
"use no memo"; // opts out this component from being compiled by React Compiler
// ...
}