From 0787971b8bbcd16794038799bd836b857ed9e9e2 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 28 Jan 2026 19:38:42 +0000 Subject: [PATCH 1/5] Add blog post: Build a React Website With Dart Tutorial covering dart_node_react package with working code examples for state management, hooks, forms, and component composition. https://claude.ai/code/session_01VeoxZJHrTkkuwC3oABbwhN --- .../src/blog/build-react-website-with-dart.md | 343 ++++++++++++++++++ 1 file changed, 343 insertions(+) create mode 100644 website/src/blog/build-react-website-with-dart.md diff --git a/website/src/blog/build-react-website-with-dart.md b/website/src/blog/build-react-website-with-dart.md new file mode 100644 index 0000000..7ade420 --- /dev/null +++ b/website/src/blog/build-react-website-with-dart.md @@ -0,0 +1,343 @@ +--- +layout: layouts/blog.njk +title: "Build a React Website With Dart" +description: "Learn how to build type-safe React web applications using Dart and the dart_node_react package. Step-by-step tutorial with working code examples." +date: 2026-01-28 +author: "dart_node team" +category: tutorials +tags: + - react + - dart + - frontend + - tutorial + - web-development +--- + +Want to build React websites with Dart instead of JavaScript or TypeScript? The **dart_node_react** package makes this possible with full type safety and familiar React patterns. This tutorial walks you through building a React web application entirely in Dart. + +## Why Build React Apps with Dart? + +React developers often wish TypeScript's types existed at runtime. Dart solves this problem. Types are checked at compile time *and* runtime. Null safety is sound. When you write Dart code, you know exactly what types you're working with. + +Flutter developers already know Dart. With dart_node_react, you can use those same skills to build React web applications. Share code between Flutter and React. Use one language across your entire stack. + +## Setting Up Your Project + +Create a new Dart project for your React frontend: + +```bash +mkdir my_react_app && cd my_react_app +dart create -t package . +``` + +Add the required dependencies to your `pubspec.yaml`: + +```yaml +name: my_react_app +environment: + sdk: ^3.0.0 + +dependencies: + dart_node_core: ^0.1.0 + dart_node_react: ^0.1.0 +``` + +Run `dart pub get` to install the packages. + +## Your First React Component + +Create a file at `web/app.dart`. This is your application entry point: + +```dart +import 'dart:js_interop'; +import 'package:dart_node_react/dart_node_react.dart'; + +void main() { + final root = Document.getElementById('root'); + (root != null) + ? ReactDOM.createRoot(root).render(App()) + : throw StateError('Root element not found'); +} + +ReactElement App() => createElement( + ((JSAny props) { + return div( + className: 'app', + children: [ + h1('Hello from Dart!'), + pEl('This React app is built entirely with Dart.'), + ], + ); + }).toJS, +); +``` + +The `createElement` function wraps your component logic. Inside, you return React elements using helper functions like `div`, `h1`, and `pEl` (for paragraph elements). + +## Managing State with Hooks + +dart_node_react provides type-safe React hooks. The `useState` hook manages component state: + +```dart +ReactElement Counter() => createElement( + ((JSAny props) { + final count = useState(0); + + return div( + className: 'counter', + children: [ + h2('Count: ${count.value}'), + button( + text: 'Increment', + onClick: (_) => count.setWithUpdater((c) => c + 1), + ), + button( + text: 'Reset', + onClick: (_) => count.set(0), + ), + ], + ); + }).toJS, +); +``` + +The `useState` hook returns a `StateHook` object with: + +- `value` - the current state value +- `set(newValue)` - replaces the state +- `setWithUpdater((oldValue) => newValue)` - updates based on previous state + +## Handling User Input + +Building forms requires handling input events. Here's a login form example: + +```dart +ReactElement LoginForm() => createElement( + ((JSAny props) { + final emailState = useState(''); + final passwordState = useState(''); + final errorState = useState(null); + + void handleSubmit() { + if (emailState.value.isEmpty || passwordState.value.isEmpty) { + errorState.set('Please fill in all fields'); + return; + } + // Submit login request + print('Logging in: ${emailState.value}'); + } + + return div( + className: 'login-form', + children: [ + h2('Sign In'), + if (errorState.value != null) + div(className: 'error', child: span(errorState.value!)), + input( + type: 'email', + placeholder: 'Email', + value: emailState.value, + className: 'input', + onChange: (e) => emailState.set(getInputValue(e).toDart), + ), + input( + type: 'password', + placeholder: 'Password', + value: passwordState.value, + className: 'input', + onChange: (e) => passwordState.set(getInputValue(e).toDart), + ), + button( + text: 'Sign In', + className: 'btn btn-primary', + onClick: handleSubmit, + ), + ], + ); + }).toJS, +); +``` + +The `getInputValue` helper extracts the input value from change events. Call `.toDart` to convert the JavaScript string to a Dart string. + +## Side Effects with useEffect + +Load data when components mount using `useEffect`: + +```dart +ReactElement UserList() => createElement( + ((JSAny props) { + final usersState = useState>([]); + final loadingState = useState(true); + + useEffect(() { + Future loadUsers() async { + // Simulate API call + await Future.delayed(Duration(seconds: 1)); + usersState.set(['Alice', 'Bob', 'Charlie']); + loadingState.set(false); + } + + unawaited(loadUsers()); + return null; + }, []); + + return div( + className: 'user-list', + children: [ + h2('Users'), + if (loadingState.value) + span('Loading...') + else + ul( + children: usersState.value + .map((user) => li(child: span(user))) + .toList(), + ), + ], + ); + }).toJS, +); +``` + +Pass an empty list `[]` as the second argument to run the effect only on mount. Return a cleanup function or `null` if no cleanup is needed. + +## Building the HTML Structure + +dart_node_react provides functions for all standard HTML elements: + +```dart +ReactElement PageLayout() => createElement( + ((JSAny props) { + return div( + className: 'layout', + children: [ + header( + className: 'header', + child: h1('My Dart React App'), + ), + mainEl( + className: 'main-content', + children: [ + section( + className: 'hero', + children: [ + h2('Welcome'), + pEl('Build type-safe React apps with Dart.'), + ], + ), + ], + ), + footer( + className: 'footer', + child: pEl('Built with dart_node_react'), + ), + ], + ); + }).toJS, +); +``` + +Common elements include `div`, `span`, `h1`-`h6`, `pEl`, `ul`, `li`, `button`, `input`, `form`, `header`, `footer`, `mainEl`, `section`, `nav`, and `article`. + +## Compiling and Running + +Create an HTML file at `web/index.html`: + +```html + + + + + My Dart React App + + +
+ + + + + +``` + +Compile your Dart code to JavaScript: + +```bash +dart compile js web/app.dart -o web/app.dart.js +``` + +Serve the `web` directory with any static file server and open it in your browser. + +## Complete Example: Task Manager + +Here's a complete task manager component demonstrating all concepts: + +```dart +ReactElement TaskManager() => createElement( + ((JSAny props) { + final tasksState = useState>([]); + final newTaskState = useState(''); + + void addTask() { + switch (newTaskState.value.trim().isEmpty) { + case true: + return; + case false: + tasksState.setWithUpdater( + (tasks) => [...tasks, newTaskState.value], + ); + newTaskState.set(''); + } + } + + void removeTask(int index) { + tasksState.setWithUpdater((tasks) { + final updated = [...tasks]; + updated.removeAt(index); + return updated; + }); + } + + return div( + className: 'task-manager', + children: [ + h2('My Tasks'), + div( + className: 'add-task', + children: [ + input( + type: 'text', + placeholder: 'New task...', + value: newTaskState.value, + onChange: (e) => newTaskState.set(getInputValue(e).toDart), + ), + button(text: 'Add', onClick: addTask), + ], + ), + ul( + className: 'task-list', + children: tasksState.value.indexed + .map( + (item) => li( + children: [ + span(item.$2), + button( + text: 'Delete', + onClick: (_) => removeTask(item.$1), + ), + ], + ), + ) + .toList(), + ), + ], + ); + }).toJS, +); +``` + +## Next Steps + +You now have the foundation to build React websites with Dart. Explore the [dart_node_react documentation](/api/dart_node_react/) for more hooks like `useEffect`, `useMemo`, and `useCallback`. Check out the [examples repository](https://github.com/AstroCodez/dart_node/tree/main/examples/frontend) for a complete full-stack application with authentication, API calls, and WebSocket integration. + +Start building type-safe React applications with Dart today. From 4b03fd2024f056718ea0834264b206574b9b588f Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 28 Jan 2026 19:39:41 +0000 Subject: [PATCH 2/5] Make blog post more engaging and add humor Add witty commentary while keeping technical accuracy. TypeScript jokes, developer pain points, and fun closing line. https://claude.ai/code/session_01VeoxZJHrTkkuwC3oABbwhN --- .../src/blog/build-react-website-with-dart.md | 78 ++++++++++--------- 1 file changed, 43 insertions(+), 35 deletions(-) diff --git a/website/src/blog/build-react-website-with-dart.md b/website/src/blog/build-react-website-with-dart.md index 7ade420..9e906b0 100644 --- a/website/src/blog/build-react-website-with-dart.md +++ b/website/src/blog/build-react-website-with-dart.md @@ -13,24 +13,28 @@ tags: - web-development --- -Want to build React websites with Dart instead of JavaScript or TypeScript? The **dart_node_react** package makes this possible with full type safety and familiar React patterns. This tutorial walks you through building a React web application entirely in Dart. +What if you could build React apps without the existential dread of `undefined is not a function`? What if your types actually meant something at runtime? What if you never had to debug another `Cannot read property 'map' of null` error at 2 AM? -## Why Build React Apps with Dart? +Good news: you can. With **dart_node_react**, you write React applications entirely in Dart. Same React patterns you know. Real type safety you've been dreaming about. -React developers often wish TypeScript's types existed at runtime. Dart solves this problem. Types are checked at compile time *and* runtime. Null safety is sound. When you write Dart code, you know exactly what types you're working with. +## Why Dart? (Besides the Obvious Joy of Not Using JavaScript) -Flutter developers already know Dart. With dart_node_react, you can use those same skills to build React web applications. Share code between Flutter and React. Use one language across your entire stack. +Let's be honest. TypeScript was a massive improvement over JavaScript. But its types are like a bouncer who checks IDs at the door and then goes home. Once you're past the compiler, anything goes. + +Dart takes a different approach. Types exist at runtime. Null safety is sound. When your code compiles, you know your `String` is actually a `String` and not secretly `undefined` wearing a fake mustache. + +Already know Flutter? You already know Dart. Now you can use those same skills to build React web apps. One language. Full stack. No context switching between "Dart brain" and "TypeScript brain." ## Setting Up Your Project -Create a new Dart project for your React frontend: +Getting started takes about 30 seconds. Create a new Dart project: ```bash mkdir my_react_app && cd my_react_app dart create -t package . ``` -Add the required dependencies to your `pubspec.yaml`: +Add the dependencies to your `pubspec.yaml`: ```yaml name: my_react_app @@ -42,11 +46,11 @@ dependencies: dart_node_react: ^0.1.0 ``` -Run `dart pub get` to install the packages. +Run `dart pub get`. Done. No webpack config. No babel. No 47 dev dependencies fighting each other. -## Your First React Component +## Your First Component -Create a file at `web/app.dart`. This is your application entry point: +Create `web/app.dart`. This is where the magic happens: ```dart import 'dart:js_interop'; @@ -65,18 +69,18 @@ ReactElement App() => createElement( className: 'app', children: [ h1('Hello from Dart!'), - pEl('This React app is built entirely with Dart.'), + pEl('Look ma, no JavaScript!'), ], ); }).toJS, ); ``` -The `createElement` function wraps your component logic. Inside, you return React elements using helper functions like `div`, `h1`, and `pEl` (for paragraph elements). +The `createElement` function wraps your component logic. Inside, you return React elements using helper functions like `div`, `h1`, and `pEl`. It feels like React because it *is* React, just with better types. -## Managing State with Hooks +## State Management: useState Without the Guesswork -dart_node_react provides type-safe React hooks. The `useState` hook manages component state: +Here's where Dart really shines. The `useState` hook returns a `StateHook` with actual, honest-to-goodness type safety: ```dart ReactElement Counter() => createElement( @@ -101,15 +105,17 @@ ReactElement Counter() => createElement( ); ``` -The `useState` hook returns a `StateHook` object with: +Three ways to update state: + +- `count.value` - read the current value +- `count.set(5)` - set a new value directly +- `count.setWithUpdater((old) => old + 1)` - update based on previous value -- `value` - the current state value -- `set(newValue)` - replaces the state -- `setWithUpdater((oldValue) => newValue)` - updates based on previous state +No more `useState(undefined)` gymnastics. Just `useState(0)`. The compiler knows it's an `int`. -## Handling User Input +## Building Forms (The Part Everyone Dreads) -Building forms requires handling input events. Here's a login form example: +Forms don't have to be painful. Here's a login form that actually works: ```dart ReactElement LoginForm() => createElement( @@ -123,7 +129,6 @@ ReactElement LoginForm() => createElement( errorState.set('Please fill in all fields'); return; } - // Submit login request print('Logging in: ${emailState.value}'); } @@ -158,11 +163,11 @@ ReactElement LoginForm() => createElement( ); ``` -The `getInputValue` helper extracts the input value from change events. Call `.toDart` to convert the JavaScript string to a Dart string. +The `getInputValue` helper extracts input values from events. Call `.toDart` to convert JavaScript strings to Dart strings. Clean and predictable. ## Side Effects with useEffect -Load data when components mount using `useEffect`: +Need to fetch data when a component mounts? `useEffect` works exactly like you'd expect: ```dart ReactElement UserList() => createElement( @@ -172,7 +177,6 @@ ReactElement UserList() => createElement( useEffect(() { Future loadUsers() async { - // Simulate API call await Future.delayed(Duration(seconds: 1)); usersState.set(['Alice', 'Bob', 'Charlie']); loadingState.set(false); @@ -200,11 +204,11 @@ ReactElement UserList() => createElement( ); ``` -Pass an empty list `[]` as the second argument to run the effect only on mount. Return a cleanup function or `null` if no cleanup is needed. +Pass an empty list `[]` to run the effect only on mount. Return a cleanup function or `null` if you don't need cleanup. No surprises here. -## Building the HTML Structure +## All Your Favorite HTML Elements -dart_node_react provides functions for all standard HTML elements: +dart_node_react provides functions for every HTML element you need: ```dart ReactElement PageLayout() => createElement( @@ -238,11 +242,11 @@ ReactElement PageLayout() => createElement( ); ``` -Common elements include `div`, `span`, `h1`-`h6`, `pEl`, `ul`, `li`, `button`, `input`, `form`, `header`, `footer`, `mainEl`, `section`, `nav`, and `article`. +You get `div`, `span`, `h1`-`h6`, `pEl`, `ul`, `li`, `button`, `input`, `form`, `header`, `footer`, `mainEl`, `section`, `nav`, `article`, and more. Everything you need to build real UIs. ## Compiling and Running -Create an HTML file at `web/index.html`: +Create `web/index.html`: ```html @@ -260,17 +264,17 @@ Create an HTML file at `web/index.html`: ``` -Compile your Dart code to JavaScript: +Compile your Dart to JavaScript: ```bash dart compile js web/app.dart -o web/app.dart.js ``` -Serve the `web` directory with any static file server and open it in your browser. +Serve the `web` directory and open it in your browser. That's it. Your React app is running, and you didn't write a single line of JavaScript. -## Complete Example: Task Manager +## Putting It Together: A Task Manager -Here's a complete task manager component demonstrating all concepts: +Here's a complete example combining everything you've learned: ```dart ReactElement TaskManager() => createElement( @@ -336,8 +340,12 @@ ReactElement TaskManager() => createElement( ); ``` -## Next Steps +State management, event handling, list rendering. All type-safe. All Dart. + +## What's Next? + +You've got the basics. Now go build something. Explore [more hooks](/api/dart_node_react/) like `useMemo` and `useCallback`. Check out the [full-stack example](https://github.com/AstroCodez/dart_node/tree/main/examples/frontend) with authentication, API integration, and WebSocket support. -You now have the foundation to build React websites with Dart. Explore the [dart_node_react documentation](/api/dart_node_react/) for more hooks like `useEffect`, `useMemo`, and `useCallback`. Check out the [examples repository](https://github.com/AstroCodez/dart_node/tree/main/examples/frontend) for a complete full-stack application with authentication, API calls, and WebSocket integration. +No more fighting with type coercion. No more `any` escape hatches. Just clean, type-safe React apps in a language that respects your time. -Start building type-safe React applications with Dart today. +Welcome to the future. It compiles to JavaScript, but at least you don't have to write it. From 32e02d0614ee38adccd7bd262973d0a1fc336134 Mon Sep 17 00:00:00 2001 From: Christian Findlay <16697547+MelbourneDeveloper@users.noreply.github.com> Date: Thu, 29 Jan 2026 21:20:43 +1100 Subject: [PATCH 3/5] Fix versions --- website/src/blog/build-react-website-with-dart.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/src/blog/build-react-website-with-dart.md b/website/src/blog/build-react-website-with-dart.md index 9e906b0..d2e3ae5 100644 --- a/website/src/blog/build-react-website-with-dart.md +++ b/website/src/blog/build-react-website-with-dart.md @@ -42,8 +42,8 @@ environment: sdk: ^3.0.0 dependencies: - dart_node_core: ^0.1.0 - dart_node_react: ^0.1.0 + dart_node_core: ^0.11.0-beta + dart_node_react: ^0.11.0-beta ``` Run `dart pub get`. Done. No webpack config. No babel. No 47 dev dependencies fighting each other. From 97733f28c17a06e0e194e367d1cd0182ee571c0e Mon Sep 17 00:00:00 2001 From: Christian Findlay <16697547+MelbourneDeveloper@users.noreply.github.com> Date: Thu, 29 Jan 2026 21:24:35 +1100 Subject: [PATCH 4/5] Fix css --- website/src/assets/css/styles.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/assets/css/styles.css b/website/src/assets/css/styles.css index 9381ee8..0c4cd5e 100644 --- a/website/src/assets/css/styles.css +++ b/website/src/assets/css/styles.css @@ -228,7 +228,7 @@ code { padding: 0.2em 0.4em; background: var(--code-bg); border-radius: var(--radius-sm); - color: var(--color-secondary); + color: var(--color-primary-light); word-break: break-word; } From f4c6b931063adea6b1c62a92d42cd9cf80f3e096 Mon Sep 17 00:00:00 2001 From: Christian Findlay <16697547+MelbourneDeveloper@users.noreply.github.com> Date: Thu, 29 Jan 2026 21:27:59 +1100 Subject: [PATCH 5/5] Add unawaited to cspell dictionary --- cspell-dictionary.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/cspell-dictionary.txt b/cspell-dictionary.txt index 7cc9e0e..0b97f57 100644 --- a/cspell-dictionary.txt +++ b/cspell-dictionary.txt @@ -111,6 +111,7 @@ nullables async awaitable awaited +unawaited pubsub socketio retryable