Skip to content

Commit ecfcee1

Browse files
committed
#7097 WIP
1 parent dcd6c1d commit ecfcee1

1 file changed

Lines changed: 53 additions & 74 deletions

File tree

Lines changed: 53 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,111 +1,90 @@
1-
# Beyond Hooks: Why Neo.mjs Reimagined Functional Components
1+
# Beyond Hooks: A New Breed of Functional Components for a Multi-Threaded World
22

3-
If you've worked with modern JavaScript frameworks, you're familiar with functional components and hooks. They were a massive leap forward, allowing us to co-locate state and logic. But as our applications have grown, we've discovered the sharp edges of this model: the complex dependency arrays, the foot-guns of stale closures, and the mental overhead of `useMemo` and `useCallback` to prevent performance issues.
3+
If you're a seasoned React developer, you've mastered the art of hooks. You know how to build complex, stateful UIs with `useState`, `useEffect`, and `useMemo`. You also know the trade-offs—the intricate dependency arrays, the constant battle against unnecessary re-renders, and the "memoization tax" you pay to keep your application performant.
44

5-
But what if the functional component model you know is just a stepping stone? What if it could be more predictable, more performant, and free from these complexities by design?
5+
We've been taught that these trade-offs are fundamental to the functional component model. But what if they aren't? What if they are merely symptoms of a single-threaded architecture?
66

7-
In Neo.mjs v10, functional components aren't just a new API. They are the ultimate expression of our new, hyper-efficient reactive core. We didn't build them to copy other frameworks; we built them because our architecture unlocked a better way to write UIs.
7+
This article will show you a new breed of functional component, born from a multi-threaded world, that eliminates these compromises by design. We didn't build them to copy other frameworks; we built them because our architecture unlocked a better way to write UIs.
88

99
---
1010

11-
### The "Why": The Problem of Fragmented Logic
11+
### The Architectural Divide: Why Your Component's Environment Matters
1212

13-
Let's be honest: even in a well-structured class-based component, UI logic can become scattered. Imagine a simple button whose appearance depends on multiple state properties. In a classic component, the logic might look like this:
13+
Before we dive into the API, we have to address the fundamental difference that changes everything. In a traditional framework like React, your component function, its state, its reconciliation (diffing), and its DOM manipulation all happen on the **same main thread** that is responsible for user interactions.
1414

15-
```javascript
16-
// A conceptual classic component
17-
class MyButton extends Neo.component.Base {
18-
static config = {
19-
text_: 'Click Me',
20-
iconCls_: null,
21-
state_: 'idle' // idle, busy, success
22-
}
15+
In Neo.mjs, the architecture is fundamentally different:
2316

24-
afterSetText(value, oldValue) {
25-
this.updateVdom();
26-
}
17+
1. **Your Application Logic (including your component's `createVdom` function) runs in a dedicated App Worker.**
18+
2. **The VDOM diffing happens in a separate VDom Worker.**
19+
3. **The Main Thread is left with one primary job: applying the calculated DOM patches.**
2720

28-
afterSetIconCls(value, oldValue) {
29-
this.updateVdom();
30-
}
21+
This isn't just a minor difference; it's a paradigm shift. Your component code is decoupled from the rendering engine, which allows for a level of performance and predictability that is architecturally impossible on the main thread.
3122

32-
afterSetState(value, oldValue) {
33-
// Maybe we change the text and icon based on state?
34-
if (value === 'busy') {
35-
this.text = 'Working...';
36-
this.iconCls = 'fa fa-spinner fa-spin';
37-
} else {
38-
// ... reset to original values
39-
}
40-
this.updateVdom();
41-
}
42-
}
43-
```
23+
---
4424

45-
The logic that determines the button's final appearance is spread across three different `afterSet` hooks. To understand the component, you have to piece together the logic from multiple places. This is the mess that makes complex UIs hard to reason about.
25+
### Deconstructing the "React Tax": How a New Architecture Solves Old Problems
4626

47-
---
27+
Let's tackle the compromises you've learned to live with, one by one, and show how a multi-threaded architecture solves them at their root.
4828

49-
### The New Foundation: UI as a Function of State
29+
#### 1. The Problem: Cascading Re-Renders & The `memo` Tax
5030

51-
The solution to this fragmentation is to have a single place where the UI is defined. In our main v10 article, we introduced our new `Effect` system. The core principle is simple: **the UI is a pure function of state. When state changes, the UI re-creates itself automatically.**
31+
**The React Way:** You know the drill. A state change in a parent component triggers a re-render. By default, React then re-renders **all of its children**, whether their props have changed or not. To prevent this performance drain, you are forced to pay the `memo` tax: wrapping components in `React.memo()`, manually memoizing functions with `useCallback()`, and objects with `useMemo()`. This manual optimization becomes a core, and often frustrating, part of the development process.
5232

53-
The `createVdom` method in a Neo.mjs functional component is, conceptually, one giant `Effect`. It automatically subscribes to every piece of reactive state it reads. This is the magic that eliminates the need for manual dependency tracking or `this.update()` calls.
33+
**The Neo.mjs Solution: Surgical Effects, Not Brute-Force Renders**
5434

55-
### The "How": Building with the Grain of the Reactive Core
35+
Our `createVdom` method is a surgical `Effect`. It automatically and precisely tracks every piece of reactive state it reads. When a piece of state changes, **only the specific `createVdom` effects that depend on that exact piece of state are queued for re-execution.**
5636

57-
With this new foundation, the API for functional components becomes incredibly intuitive and powerful.
37+
There are no cascading re-renders. If a parent's `createVdom` re-runs, but the configs passed to a child have not changed, the child component's `createVdom` function is **never executed**.
5838

59-
**`defineComponent` & `createVdom`: Your Single Source of Truth**
39+
This means `memo`, `useCallback`, and `useMemo` are not needed. The architecture is efficient by default, eliminating an entire class of performance optimizations and bugs.
6040

61-
All the logic for your component's output now lives in one, easy-to-read function. There's no more hunting through different methods to understand how the UI will look.
41+
#### 2. The Problem: The Boilerplate of Immutability
42+
43+
**The React Way:** To change a nested object in React state, you have to meticulously reconstruct the object path with spread syntax (`...`), creating new references for every level. This is required to signal to React's diffing algorithm that something has changed.
6244

6345
```javascript
64-
import {defineComponent, useConfig} from 'neo.mjs/functional';
65-
66-
export default defineComponent({
67-
createVdom(config) {
68-
const [state, setState] = useConfig('idle');
69-
70-
let text = config.text;
71-
let iconCls = config.iconCls;
72-
73-
if (state === 'busy') {
74-
text = 'Working...';
75-
iconCls = 'fa fa-spinner fa-spin';
76-
}
77-
78-
return {
79-
tag: 'button',
80-
className: 'my-button',
81-
cn: [
82-
{tag: 'i', className: iconCls},
83-
{tag: 'span', text: text}
84-
]
85-
}
46+
// The familiar immutable update dance
47+
setState(prevState => ({
48+
...prevState,
49+
deeply: {
50+
...prevState.deeply,
51+
nested: {
52+
...prevState.deeply.nested,
53+
property: 'new value'
8654
}
87-
});
55+
}
56+
}));
8857
```
8958

90-
**`useConfig` and Named Configs: The Inputs to Your Function**
59+
**The Neo.mjs Solution: Mutability for You, Immutability for the Machine**
60+
61+
We believe the developer should not carry this cognitive load. In Neo.mjs, you can just mutate the state directly. It's simple and intuitive.
62+
63+
```javascript
64+
// Just change the value. That's it.
65+
this.myObject.deeply.nested.property = 'new value';
66+
```
67+
68+
How does it work? When an update is triggered, the framework handles creating an immutable JSON snapshot of the VDOM for the diffing process in the VDom Worker. We provide the best of both worlds: simple, direct mutation for the developer and a safe, immutable structure for the high-performance diffing algorithm.
69+
70+
#### 3. The Problem: The "SSR and Hydration is the ONLY way" Mindset
9171

92-
Your `createVdom` function is driven by two types of inputs:
72+
**The React/Next.js Way:** The industry has invested heavily in Server-Side Rendering and hydration to improve perceived performance and SEO. For content-heavy sites, this is a valid strategy. But for complex, stateful Single-Page Applications, it introduces immense complexity: the "hydration crisis," the difficulty of managing server vs. client components, and the fact that after all that work, your application is *still* running on the client's main thread.
9373

94-
1. **`useConfig` (Internal State):** This is for state that is private to your component. Crucially, calling `setState('busy')` doesn't just change a value; it triggers the re-execution of the entire `createVdom` function, guaranteeing a consistent UI every time.
95-
2. **Named Configs (Public API):** These are the "props" or external inputs to your reactive function, defined in the `static config` block (e.g., `text_`). They are the declarative way to control your component from the outside.
74+
**The Neo.mjs Solution: Blueprints, Not Dehydrated HTML**
9675

97-
Because the entire VDOM is recreated from scratch on every change, you can be confident that the UI is always a perfect reflection of the current state. The reactive core is so efficient that this "brute force" approach is faster than manually trying to optimize updates.
76+
We offer a more robust and scalable model for SPAs. Instead of sending pre-rendered HTML that needs to be brought back to life, we can send a compact **JSON blueprint**. The client-side engine, running in a worker, constructs the live, interactive UI from this blueprint. This is a more efficient, more predictable, and architecturally cleaner way to build complex applications that are not primarily focused on static content.
9877

9978
---
10079

101-
### The AI Connection: Predictability for Human and Machine
80+
### The AI Connection: The Inevitable Next Step
10281

103-
This architecture isn't just better for you; it's essential for an AI co-developer. Because `createVdom` is a pure function of its inputs (`config` and `useConfig`), an AI can reliably change the UI by simply changing the data. It doesn't need to understand a complex class lifecycle or a web of `afterSet` hooks. This makes AI-driven UI generation dramatically simpler and more robust.
82+
This blueprint-first, surgically reactive, and mutable-by-default model isn't just better for you; it's the architecture an AI would choose. An AI can easily generate and manipulate a structured JSON blueprint, but it struggles to generate flawless, complex JSX. By building on these principles, you are not just using a new framework; you are future-proofing your skills for the AI era.
10483

10584
---
10685

107-
### Conclusion: A More Evolved Functional Component
86+
### Conclusion: A Different Philosophy, A Better Component
10887

109-
The functional component model in Neo.mjs v10 is not just another implementation of hooks. It is a fundamentally more robust and performant model for the future of UI development. By centralizing logic in a single reactive function, we eliminate an entire class of bugs, reduce cognitive overhead, and create an architecture that is ready for the AI era.
88+
Neo.mjs functional components are not a "React clone." They are a re-imagining of what a functional component can be when freed from the constraints of the main thread. They offer a development experience that is not only more performant by default but also simpler, more predictable, and ready for the next generation of web development.
11089

111-
In our next deep dive, we'll explore the engine that powers all of this: the new Two-Tier Reactivity system.
90+
In our next deep dive, we'll explore the engine that powers all of this: the new Two-Tier Reactivity system.

0 commit comments

Comments
 (0)