m()
Syntax: m(tag, props?, children?, flag?, delta?, hook?)
Example: m('div', { id: 'app' }, ['Hello World'])
It is recommended that you use m
to create a VNode. It accepts a tag as a string, an optional props object, an optional array of children, and an optional flag.
import { m } from 'million';
const vnode = m('div', { id: 'app' }, ['Hello World']);
{
tag: 'div',
props: {
id: 'app'
},
children: ['Hello World'],
}
The tagName
is stored under the tag
, attributes
and properties are stored under props
, and the children are stored under children
.
REPL
You can enter HTML and it will automatically convert to a VNode if you are confused on how the raw data representation looks.
Optimization via keys
Most of the time, the diffing and patching process is fast enough, but when dealing with a large amount of children, it is best to provide runtime hints through keys. You can attach a key
under props. When patched, it will only diff props and children if the key
is changed. For more advanced runtime diffing using keys, check out Flags.ELEMENT_KEYED_CHILDREN
.
import { m } from 'million';
const vnode = m('div', { key: 'foo' }, ['Hello World']);
{
tag: 'div',
props: {},
children: ['Hello World'],
key: 'foo',
}
className
and style
props helpers
The className
and style
props need to be preprocessed using the className
and style
functions to convert objects to strings. The class object syntax allows for you to toggle classes based on a boolean value. The style object syntax allows you to set styles in a clean format.
import { m, className, style } from 'million';
const vnode = m(
'div',
{
className: className({ class1: true, class2: false, class3: 1 + 1 === 2 }),
style: style({ color: 'black', 'font-weight': 'bold' }),
},
['Hello World'],
);
{
tag: 'div',
props: {
className: 'class1 class3',
style: 'color:black;font-weight:bold'
},
children: ['Hello World'],
}
kebab
props helper
Generally, the values of className
and style
props are objects in kebab-case. However, if you want to use camelCase for the keys of these props, you can use the kebab
function to convert the keys from camelCase to kebab-case.
import { m, style, kebab } from 'million';
const vnode = style(kebab({ color: 'black', fontWeight: 'bold' }));
{
tag: 'div',
props: {
style: 'color:black;font-weight:bold'
},
children: ['Hello World'],
}
SVG support
SVGs are handled by default, but sometimes you need to attach SVG namespaces. SVGs are processed using the svg
function to add ns
props to the element and all of the children of that element.
import { m, svg } from 'million';
const vnode = svg(m('svg'));
{
tag: 'svg',
props: {
ns: 'http://www.w3.org/2000/svg'
},
}
Lifecycle hook
properties
The lifecycle hook
properties allows you to "hook in" to the diffing and patching process. There are four hooks: 'create'
, 'update'
, 'remove'
, and one 'diff'
control flow hook. Every hook, if defined, must return a boolean, which will determine whether the code runs of not (true
runs, false
doesn't run).
import { _, m } from 'million';
const vnode = m(
'div',
_ /* props */,
_ /* children */,
_ /* flag */,
_ /* delta */,
{
create: (el, newVNode, oldVNode) => {
console.log('create was called!', el);
return true;
},
update: (el, newVNode, oldVNode) => {
console.log('update was called!', el);
return true;
},
remove: (el, newVNode, oldVNode) => {
console.log('remove was called!', el);
return true;
},
diff: (el, newVNode, oldVNode) => {
console.log('diff was called!', el);
return true;
},
},
);
If you have multiple hooks, you can merge them easily with the mergeHooks
function:
import { mergeHooks } from 'million';
const firstHook = {
create: () => {
console.log(1);
return true;
},
};
const secondHook = {
create: () => {
console.log(2);
return true;
},
update: () => {
console.log('Hello World!');
return true;
},
};
const finalBossHook = mergeHooks([firstHook, secondHook]);
As a result, finalBossHook
becomes:
const finalBossHook = {
create: () => {
console.log(1); // From firstHook
console.log(2); // From secondHook
return true;
},
update: () => {
console.log('Hello World!'); // from secondHook
return true;
},
};