refflex
Version:
A declarative UI enhancement library for React apps
298 lines (217 loc) • 9.29 kB
Markdown
# Reflex
A next-generation declarative UI framework for React — designed to replace imperative logic, external API chaos, and hook soup with clean, structured, and AI-friendly components.
⸻
## Overview
Reflex is a radical rethinking of how UI logic, external APIs, and side effects are expressed in React applications. It introduces a unified declarative programming model that replaces scattered useState, useEffect, addEventListener, setTimeout, fetch, and custom imperative logic with clear, expressive components that describe what should happen, not how.
With Reflex, everything becomes declarative — from reactive state and conditionals to external APIs like WebSockets, timers, media queries, and even browser events. It turns asynchronous flows, interaction logic, and lifecycle concerns into composable building blocks that can be reasoned about visually, reused safely, and understood instantly.
This structure isn't just better for humans — it's dramatically more AI-friendly. By eliminating the ambiguity and noise of imperative glue code, Reflex enables AI copilots to assist more effectively, suggest accurate completions, detect side effects, and reason about behavior with confidence.
Whether you're building interactive dashboards, realtime apps, or animation-heavy interfaces, Reflex helps you create clean, predictable UIs without drowning in hooks, conditions, or plumbing.
⸻
Reflex is still in active development — and we're building toward a fully declarative future for frontend development. Contributions, feedback, and use cases are warmly welcomed.
## Installation
```bash
npm install reflex
```
## Key Components
### Signal (Alternative to useState)
Signal provides a more flexible state management solution compared to useState. Unlike useState which is tied to a specific component, Signal can be shared across components and automatically tracks dependencies.
```jsx
import { createSignal, S } from 'reflex';
// Create a signal outside of components
const count = createSignal(0);
function Counter() {
return (
<div>
{/* S component automatically subscribes to changes */}
<p>Count: <S>{count}</S></p>
<button onClick={() => count.set(count.peek() + 1)}>Increment</button>
</div>
);
}
```
### WebSocket Integration
Reflex provides a declarative way to work with WebSockets, handling connection management and cleanup automatically:
```jsx
import { WebSocketProvider, OnMessage, OnOpen, OnClose, useWebSocket } from 'reflex';
function WebSocketExample() {
return (
<WebSocketProvider url="wss://echo.example.com">
<OnOpen>
{(event) => console.log('Connected to WebSocket server')}
</OnOpen>
<OnMessage>
{(event) => console.log('Received message:', event.data)}
</OnMessage>
<OnClose>
{(event) => console.log('Disconnected from WebSocket server')}
</OnClose>
<button onClick={() => {
const socket = useWebSocket();
if (socket) {
socket.send('Hello, WebSocket!');
}
}}>
Send Message
</button>
</WebSocketProvider>
);
}
```
### Push Notifications
Handle browser notifications with a clean component-based approach:
```jsx
import { PushNotification } from 'reflex';
function NotificationExample() {
return (
<PushNotification
askPermission={true}
onGranted={() => console.log('Notification permission granted')}
onDenied={() => console.log('Notification permission denied')}
onMessage={(data) => console.log('Received notification:', data)}
/>
);
}
```
### Resource Component
Handle asynchronous operations declaratively without complex useState/useEffect combinations:
```jsx
import { Resource, ResourcePending, ResourceFulfilled, ResourceRejected } from 'reflex';
function ResourceExample() {
const fetchData = async () => {
const response = await fetch('https://api.example.com/data');
return response.json();
};
return (
<Resource task={fetchData}>
<ResourcePending>
<p>Loading data...</p>
</ResourcePending>
<ResourceFulfilled>
{(data) => (
<div>
<h3>Data loaded successfully!</h3>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
)}
</ResourceFulfilled>
<ResourceRejected>
{(error) => (
<div>
<h3>Error loading data</h3>
<p>{error.message}</p>
</div>
)}
</ResourceRejected>
</Resource>
);
}
```
### Loop Component
Iterate over arrays or signals with automatic updates when data changes:
```jsx
import { Loop, createSignal, S } from 'reflex';
function LoopExample() {
const items = createSignal(['Item 1', 'Item 2', 'Item 3']);
return (
<div>
<Loop each={items}>
{(item, index) => (
<div>
<p>{item}</p>
<button onClick={() => {
const newItems = [...items.peek()];
newItems.splice(index, 1);
items.set(newItems);
}}>
Remove
</button>
</div>
)}
</Loop>
<button onClick={() => items.set([...items.peek(), `Item ${items.peek().length + 1}`])}>
Add Item
</button>
<p>Total items: <S>{items.get().length}</S></p>
</div>
);
}
```
### VirtualList
Efficiently render large lists by only rendering the visible items:
```jsx
import { VirtualList, createSignal, S } from 'reflex';
function VirtualListExample() {
// Create a large array of items as a signal
const items = createSignal(
Array.from({ length: 10000 }, (_, i) => `Item ${i + 1}`)
);
return (
<div>
<p>Showing <S>{items.get().length}</S> items</p>
<VirtualList
items={items}
height={400}
estimatedItemHeight={50}
>
{(item, index) => (
<div style={{ padding: '20px', borderBottom: '1px solid #eee' }}>
{item} (index: {index})
</div>
)}
</VirtualList>
</div>
);
}
```
## Other Components
Reflex includes many other useful components:
- **When**: Conditional rendering
- **Cond/Otherwise**: Multi-branch conditional rendering
- **OnMount/OnUpdate**: Lifecycle hooks as components
- **AnimatePresence**: Animation coordination
- **Portal**: Render content in a different DOM node
- **Action**: Declarative side effects
- **BindInput/BindText**: Two-way binding for form elements
## Viewing Components in Storybook
To see all the components in action and explore their capabilities, run the following command:
```bash
npm run storybook
```
This will start the Storybook development server, allowing you to browse and interact with all the components in an isolated environment.
## Philosophy
The main philosophy of Reflex is to avoid mixing imperative code with declarative code, even when using JSX elements with arrow functions. This separation makes your code more maintainable, easier to reason about, and less prone to bugs.
Traditional React components often mix imperative logic (like state updates, side effects, and event handlers) with declarative UI rendering. This can lead to complex, hard-to-maintain components. Reflex provides a more structured approach by encapsulating common patterns in declarative components.
## Roadmap
Reflex is actively being developed with several exciting features on the horizon:
### Server-Side Rendering (SSR) Support
We're working on adding full SSR support to make Reflex compatible with frameworks like Next.js and Remix. This will allow you to use Reflex components in server-rendered applications.
### More Common APIs
We're expanding our library to include more declarative wrappers for common browser APIs and patterns that developers frequently need to reimplement, such as:
- Form validation
- Internationalization (i18n)
- Authentication flows
- Drag and drop
- Keyboard shortcuts
- Clipboard operations
- Local storage/session storage
### External Library Adapters
To improve interoperability with the React ecosystem, we're developing adapters for popular external libraries. These adapters will provide a consistent, declarative interface for using third-party components within the Reflex philosophy:
- UI component libraries (Material UI, Chakra UI, etc.)
- Animation libraries (Framer Motion, React Spring)
- Form libraries (React Hook Form, Formik)
- State management libraries (Redux, Zustand, Jotai)
## Requirements
- React 19 or higher
- React DOM 19 or higher
## Contributing
We welcome contributions to Reflex! If you're interested in helping improve the library, please feel free to submit pull requests or open issues on our GitHub repository.
## ✍️ Author
This project was created by [Renato Lovizotto](https://github.com/renatolovizotto).
Please give proper credit if you fork, extend, or reference this work.
## License
MIT
🙏 Reflex is licensed under MIT to support openness and learning.
> Please respect the spirit of the project: don't rebrand or commercialize it without attribution or meaningful changes.
## ☕ Support Reflex
If this project helps you, consider supporting:
👉 [buymeacoffee.com/lovizotto](https://buymeacoffee.com/lovizotto)