
Security News
The Hidden Blast Radius of the Axios Compromise
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.
A React-like library with reactive signals and computed values for building dynamic web applications—without the need for JSX
A React-like library with reactive signals and computed values for building dynamic web applications—without the need for JSX.
⚠️ Proof of Concept Warning ⚠️
This project is currently a proof of concept and is not suitable for production use. It's designed to explore reactive programming patterns and demonstrate an alternative approach to React.
Think of it as a "what if React was simpler?" experiment. Use at your own risk! 🧪
If you want something stable for production, this is not it (yet).
React has transformed web development, making it straightforward to build complex, interactive UIs with reusable components. Its approach to rendering and UI composition has become the industry standard. However, state management in React has long been a source of frustration. Whether it's prop drilling, context, Redux, hooks, or ongoing debates about the "best" way to handle state, managing state in React often feels unnecessarily complicated. Thorix is designed to change that—offering simple, reactive, and intuitive state management, so you can keep your UI in sync without the hassle of hooks or boilerplate.
React appears to have reached its peak. Meaningful progress likely requires a different foundation—not more layers on the same model. Recent releases skew toward additive features and ergonomic tweaks, while core pain points remain: state complexity, re-render churn, and mental overhead. Thorix explores a simpler, signal-first approach that addresses those fundamentals directly.
React is great and all... but honestly, it's kind of like using a chainsaw to slice a loaf of bread. Sure, it gets the job done, but is all that machinery—virtual DOM, reconciliation, and a sprawling state system—really needed just to update a simple counter?
This isn't to say React is bad — it often solves problems that don't always need solving. Sometimes updating the DOM directly is enough, without the overhead of a virtual DOM, reconciliation, and the entire React ecosystem. 🎯
Signals are fundamentally better than React hooks because:
useEffect dependency hell!)Pure TypeScript is better than JSX because:
Time to address the elephant in the room: defaulting to React by habit.
React is ubiquitous—in job postings, tutorials, bootcamps, and portfolios. That ubiquity can make it the default, but the default isn't always the right tool for the job.
Sometimes a sledgehammer (React) is perfect; sometimes a regular hammer (Thorix) is exactly right. 🛠️
Thorix is for developers who:
Remember: The best tool is the one that gets the job done with the least amount of complexity. Sometimes that's React, and sometimes it's Thorix. 🤷♂️
Time to address the elephant in the React room: hooks are a mess.
useEffect is like that friend who always shows up to your party but never knows when to leave. Here's what you're dealing with:
// React way - the useEffect dependency hell
useEffect(() => {
// Do something
}, [dependency1, dependency2, dependency3]); // Did I forget one? 🤔
// Oh wait, I need to add another dependency...
useEffect(() => {
// Do something else
}, [dependency1, dependency2, dependency3, dependency4]); // Still missing something?
// And another one for cleanup...
useEffect(() => {
const timer = setInterval(() => {
// Do something
}, 1000);
return () => clearInterval(timer); // Don't forget cleanup!
}, [dependency1, dependency2, dependency3, dependency4]); // Wait, what was I doing again?
vs Thorix signals:
// Thorix way - just update the signal
const timer = signal(0);
setInterval(() => {
timer.set(timer.get() + 1);
}, 1000);
// That's it. No cleanup, no dependencies, no useEffect hell.
// The DOM updates automatically when the signal changes.
With React hooks, you need to remember:
With Thorix signals:
In React, you never know what's going to re-render:
// React - will this re-render? Who knows!
const [count, setCount] = useState(0);
const [user, setUser] = useState({ name: 'John' });
// Does changing count re-render the user display?
// Does changing user re-render the count display?
// The answer: YES, because React re-renders the entire component!
vs Thorix:
// Thorix - only what depends on the signal updates
const count = signal(0);
const user = signal({ name: 'John' });
// Only elements that depend on count will update when count changes
// Only elements that depend on user will update when user changes
// No unnecessary re-renders, no guessing games!
React state management is like trying to organize a circus where all the performers are connected by invisible strings:
// React - state management hell
const [localState, setLocalState] = useState(0);
const [globalState, setGlobalState] = useState({});
const [formState, setFormState] = useState({});
const [uiState, setUiState] = useState({});
// Need to share state? Time for Context!
const MyContext = createContext();
const MyProvider = ({ children }) => {
const [sharedState, setSharedState] = useState({});
return (
<MyContext.Provider value={{ sharedState, setSharedState }}>
{children}
</MyContext.Provider>
);
};
// Or Redux, or Zustand, or Recoil, or...
vs Thorix:
// Thorix - just create a signal anywhere
const count = signal(0);
const user = signal({ name: 'John' });
// Use it anywhere in your app, no providers needed
// No context, no reducers, no complex state management
The bottom line: Hooks are like trying to solve a Rubik's cube blindfolded while juggling flaming torches. Signals are like having a magic wand that just works. ✨
npm install thorix
Ready to build reactive apps without the React complexity? Dive in! 🏊♂️
No virtual DOM, no reconciliation, no provider hell - just pure, simple reactivity!
import {
signal,
computed,
component,
div,
h1,
p,
button,
render,
} from 'thorix';
// Create global reactive signals - accessible anywhere in your app
const count = signal(0);
const user = signal({ name: 'John', email: 'john@example.com' });
// Create a reactive component
const Counter = component(() => {
// Create a local computed value
const doubleCount = computed(() => count.get() * 2);
// Create a reactive element
return div(
{ className: 'counter' },
h1('Counter Example'),
p('Count: ', count),
p('Double Count: ', doubleCount),
p('User: ', user.get().name),
button(
{
onClick: () => count.set(count.get() + 1),
},
'Increment',
),
);
});
// Another component can access the same global state
const UserProfile = component(() => {
return div(
{ className: 'profile' },
h1('User Profile'),
p('Name: ', user.get().name),
p('Email: ', user.get().email),
);
});
// Render to DOM
render(Counter, document.getElementById('app'));
For development setup, building, testing, and project structure, see DEVELOPMENT.md.
Thorix provides comprehensive documentation covering all aspects of the library:
Thorix uses a clean, intuitive naming convention:
component<P> - Function to create reactive components (alias for createReactiveComponent)Component<P> - Type for reactive components with propsimport { component, Component } from 'thorix';
// Component without props
const SimpleCounter = component(() => {
return div('Hello World');
});
// Component with typed props
const Greeting: Component<{ name: string }> = component((props) => {
return div(`Hello, ${props?.name || 'World'}!`);
});
// Usage
SimpleCounter();
Greeting({ name: 'Alice' });
Router Guide: Client-side routing with navigation and error handling
i18n Guide: Internationalization and localization support
For detailed API documentation, see API.md.
signal<T>(initialValue: T): Signal<T>Creates a reactive signal with an initial value.
const count = signal(0);
count.set(5); // Update value
console.log(count.get()); // Get current value
computed<T>(fn: () => T): Computed<T>Creates a computed value that automatically updates when dependencies change.
const doubleCount = computed(() => count.get() * 2);
render(element: HTMLElement, container: HTMLElement): voidRenders a reactive element into a DOM container.
render(Counter(), document.getElementById('app'));
All HTML elements are available as factory functions:
import { div, h1, p, button, input, span } from 'thorix';
const element = div(
{ className: 'container' },
h1({ children: 'Hello World' }),
p({ children: 'This is a paragraph' }),
button({ onClick: handleClick, children: 'Click me' }),
);
The examples/ directory contains comprehensive examples demonstrating Thorix features:
/random-generator): Signal updates with automatic UI re-rendering/debug): Reactive signals with disabled states and real-time logging/router): Advanced client-side routing with navigation and error handling/strongly-typed-props): Demonstrates TypeScript type safety for all HTML element props/signals): Unified signal API with preserved signals and reactive updates/classnames): Dynamic CSS class management utility/props-demo): Strongly-typed components with props and reactive updatesEach example demonstrates different aspects of Thorix:
# Run all examples simultaneously
./examples/run-all.sh
# Or run individual examples
cd examples/debug && npm install && npm run dev
cd examples/router && npm install && npm run dev
cd examples/strongly-typed-props && npm install && npm run dev
Each example runs on a different port:
http://localhost:5173http://localhost:5174http://localhost:5175http://localhost:5176http://localhost:5177http://localhost:5178For detailed information about each example, see the Examples README.
This project is licensed under the MIT License.
FAQs
A React-like library with reactive signals and computed values for building dynamic web applications—without the need for JSX
We found that thorix demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.