Lightweight, flexible, and predictable state management for modern React applications.
Blac is a state management library designed to bring simplicity and power to your React projects. It draws inspiration from established patterns like Redux and the Bloc pattern, while offering a more intuitive API and minimizing boilerplate. At its core, Blac focuses on type safety (with first-class TypeScript support) and an excellent developer experience.
It consists of two main packages:
@blac/core: The foundational library providing the core Blac/Bloc logic, instance management, and plugin system.@blac/react: The React integration layer, offering hooks and utilities to seamlessly connect Blac with your React components.
An overview of the Blac pattern, its core concepts, and how it simplifies state management in React.
- Simple API: Intuitive and easy to learn, minimizing boilerplate.
- Smart Instance Management: Automatic creation, sharing (default for non-isolated Blocs using class name or provided ID), and disposal of
Blocinstances. SupportskeepAlivefor persistent state and isolated instances (viastatic isolated = trueor unique IDs). - TypeScript First: Strong typing for robust applications and excellent developer experience.
- Extensible: Add custom functionality through a built-in plugin system or create addons for
Blocs (like thePersistaddon for storage). - Performance: Lightweight core and efficient updates.
- Flexible Architecture: Adapts to various project needs, from simple components to complex applications.
To get started with Blac in your React project, install the @blac/react package. This package includes @blac/core.
# Using pnpm (recommended for this monorepo)
pnpm add @blac/react
# Or using npm
npm install @blac/react
# Or using yarn
yarn add @blac/reactHere's a taste of how to use Blac with a simple counter:
// 1. Define your Cubit (e.g., in src/cubits/CounterCubit.ts)
import { Cubit } from '@blac/core';
interface CounterState {
count: number;
}
// CounterCubit manages the counter's state
export class CounterCubit extends Cubit<CounterState> {
constructor() {
// Initialize the state with a count of 0
super({ count: 0 });
}
// Define methods to update the state
// Remember: methods must be arrow functions to bind 'this' correctly!
increment = () => this.emit({ count: this.state.count + 1 });
decrement = () => this.emit({ count: this.state.count - 1 });
reset = () => this.emit({ count: 0 });
}
// 2. Use the Cubit in your React component (e.g., in src/components/CounterDisplay.tsx)
import { useBloc } from '@blac/react';
import { CounterCubit } from '../cubits/CounterCubit'; // Adjust path as needed
function CounterDisplay() {
// Connect your component to the CounterCubit.
// useBloc returns a tuple: [currentState, cubitInstance]
const [state, counterCubit] = useBloc(CounterCubit);
return (
<>
<h1>Count: {state.count}</h1> {/* Access state directly */}
<button onClick={counterCubit.increment}>Increment</button>
<button onClick={counterCubit.decrement}>Decrement</button>
<button onClick={counterCubit.reset}>Reset</button>
</>
);
}
export default CounterDisplay;BlocBase: The foundational abstract class for state containers.Cubit<State>: A simpler state container that exposes methods (similar to Zustand) to directlyemitorpatchnew states. The Quick Start example above uses aCubit.Bloc<State, Action>: A more advanced state container that processesActions (events) through areducerfunction (similar to Redux reducers) to produce newState. This is useful for more complex state logic where transitions are event-driven and require more structure.useBlocHook: The primary React hook from@blac/reactto connect components toBlocorCubitinstances, providing the current state and the instance itself. It efficiently re-renders components when relevant state properties change.- Instance Management: Blac's central
Blacinstance intelligently manages yourBlocs/Cubits. By default, non-isolated Blocs are shared (keyed by class name or a custom ID). Blocs can be marked asstatic isolated = trueor given unique IDs for component-specific state, and can be configured withstatic keepAlive = trueto persist in memory.
- 💡 Simple & Intuitive API: Get started quickly with familiar concepts and less boilerplate.
- 🧠 Smart Instance Management by the central
Blacclass:- Automatic creation and disposal of
Blocinstances based on usage. - Non-isolated
Blocs are shared by default (keyed by class name or custom ID). - Isolated
Blocs (markedstatic isolated = trueor given a unique ID viauseBlocoptions) for component-specific or distinct states. Blocs are kept alive as long as they have active listeners/consumers, or if explicitly marked withstatic keepAlive = true.
- Automatic creation and disposal of
- 🔒 TypeScript First: Full type safety out-of-the-box, enabling robust applications and great autocompletion.
- 🧩 Extensible via Plugins & Addons:
- Plugins: Extend Blac's core functionality by hooking into lifecycle events (e.g., for logging).
- Addons: Enhance individual
Bloccapabilities (e.g., state persistence with thePersistaddon).
- 🚀 Performance Focused:
- Minimal dependencies for a small bundle size.
- Efficient state updates and re-renders in React.
- 🧱 Flexible Architecture: Adapts to various React project structures and complexities.
For comprehensive documentation, including advanced usage, API details, and guides, please refer to:
- Local Docs: Run
pnpm run dev:docsin theapps/docsdirectory and open the provided local URL. - Online Docs: (TODO: Add link to the deployed documentation site here if available)
Contributions are highly welcome! Whether it's bug fixes, feature enhancements, or documentation improvements, please feel free to:
- Fork the repository.
- Create your feature branch (
git checkout -b feature/AmazingFeature). - Commit your changes (
git commit -m 'Add some AmazingFeature'). - Push to the branch (
git push origin feature/AmazingFeature). - Open a Pull Request.
Please ensure your code adheres to the project's linting and formatting standards.
Blac is MIT licensed.