Hooks Storage
O! uses a global hooks system that stores component state between renders.Global Hooks Array
When a component renders, O! maintains:hooks- Global array storing all hooks for the current componentindex- Current position in the hooks array (starts at 0)forceUpdate- Function that triggers a re-render
How Hooks Are Stored
Each component instance has its own hooks array stored on the DOM node:k (either explicit via p.k or auto-generated), and its hooks array persists between renders.
Why Hook Order Matters
Why Hook Order Matters
Since hooks are stored in an array and accessed by index, you must call hooks in the same order every render. If you conditionally call hooks or call them in loops, the index will be wrong and you’ll get state from the wrong hook.
Render and Diffing Algorithm
O! uses a simple virtual DOM diffing algorithm to update the real DOM efficiently.Render Process
Therender() function (o.mjs:251) follows these steps:
- Convert to array:
vlist = [].concat(vlist)ensures we always work with an array - Process each virtual node: For each node in the virtual tree:
- Set up
forceUpdateto re-render this tree - If node is a function (component), call it to get the real virtual node
- Create or reuse DOM nodes
- Patch properties
- Recursively render children
- Set up
- Fire useEffect callbacks: After rendering is complete
- Clean up removed nodes: Call cleanup functions for unmounted components
The Diffing Algorithm
From o.mjs:282-285:- Position-based matching: Compares virtual nodes to DOM nodes by array index
- Tag/text comparison: If tags match (for elements) or text matches (for text nodes), reuse the node
- Otherwise: Create and insert a new node
- No key-based diffing (except for component state)
- No move operations - only create/update/remove
- Linear scan, no optimization
Property Patching
Property Patching
For each element property (o.mjs:288-296):O! sets properties directly on DOM nodes (not attributes), except for SVG elements which use
setAttribute. This is why you use className instead of class.Force Update Mechanism
When you call a state setter (fromuseState or useReducer), it triggers a re-render:
forceUpdate function is set during render to call render(vlist, dom) with the same arguments, causing the entire component tree to be re-evaluated.
Template Parser (x“)
Thex template tag parser converts HTML-like strings into virtual nodes.
Parser Modes
The parser is a state machine with three modes (o.mjs:55-58):How Parsing Works
MODE_TEXT: Between Tags
MODE_TEXT: Between Tags
MODE_OPEN_TAG: Reading Attributes
MODE_OPEN_TAG: Reading Attributes
From o.mjs:92-111:In open tag mode, the parser reads attribute key-value pairs and adds them to the current node’s properties object.
MODE_CLOSE_TAG: Closing Tags
MODE_CLOSE_TAG: Closing Tags
Stack-Based Parsing
The parser uses a stack to handle nested tags (o.mjs:52):- Opening tags push new
h()nodes onto the stack - Closing tags (or self-closing tags) pop from stack and add to parent
- The final result is
stack[0].c[0]- the first child of the fake root
Template Placeholders
Placeholders (the${...} expressions) are handled by the readToken function (o.mjs:61-68):
readToken returns the corresponding field value from the template arguments.
useEffect Execution
After rendering completes, O! executes alluseEffect callbacks (o.mjs:302-306):
Summary
O!‘s internals are deliberately simple:- Hooks: Stored in arrays on DOM nodes, accessed by key and index
- Diffing: Position-based comparison with create/update/remove operations
- forceUpdate: Re-runs render with the same arguments
- Parser: State machine that builds a stack of virtual nodes from HTML-like templates