π Olova.js
A lightweight, reactive JavaScript framework for building modern web
applications. Olova.js provides a simple yet powerful API for creating reactive
UIs with JSX support.
β¨ Features
- π― Signals - Reactive state management
- π Effects - Automatic dependency tracking and side effects
- π Memos - Computed values with dependency tracking
- π¨ JSX Support - Write components using familiar JSX syntax
- π Components - Function-based component system
- π Refs - Direct DOM node references
- πͺ Lifecycle Hooks -
onMount
andonUnmount
for component lifecycle management - 𧩠Fragments - Support for multiple root elements
- π¨ SVG Support - First-class SVG element support
π¦ Installation
# Create a new project (recommended)
npm create vilo@latest
# Or install directly in an existing project
npm install olova
For now, you can use it directly in your project by copying the core files.
π Quick Start Guide
1. Basic Counter Example
A simple counter showing reactive state management:
import { render, setSignal } from "./core/core.js";
const Counter = () => {
const [count, setCount] = setSignal(0);
return (
<div>
<h1>{() => count()}</h1>
<button onClick={() => setCount(count() + 1)}>Increment</button>
</div>
);
};
2. Multiple Elements with Fragment
Using fragments to render multiple elements:
import { render, Fragment } from "./core/core.js";
const MultipleElements = () => {
return (
<>
<div>First</div>
<div>Second</div>
</>
);
};
3. Effects and Reactivity
Demonstrating reactive effects:
import { render, setSignal, setEffect } from "./core/core.js";
const EffectsExample = () => {
const [name, setName] = setSignal("John");
setEffect(() => {
console.log(`Name changed to: ${name()}`);
});
return (
<div>
<input
value={() => name()}
onInput={(e) => setName(e.target.value)}
type="text"
/>
<p>Current name: {() => name()}</p>
</div>
);
};
4. Computed Values with Memos
Using memos for derived state:
import { render, setSignal, setMemo } from "./core/core.js";
const MemoExample = () => {
const [firstName, setFirstName] = setSignal("John");
const [lastName, setLastName] = setSignal("Doe");
const fullName = setMemo(() => `${firstName()} ${lastName()}`);
return (
<div>
<input
value={() => firstName()}
onInput={(e) => setFirstName(e.target.value)}
placeholder="First Name"
/>
<input
value={() => lastName()}
onInput={(e) => setLastName(e.target.value)}
placeholder="Last Name"
/>
<p>Full name: {() => fullName()}</p>
</div>
);
};
5. DOM References with Refs
Direct DOM manipulation using refs:
import { render, setRef } from "./core/core.js";
const RefsExample = () => {
const inputRef = setRef();
return (
<div>
<input ref={inputRef} type="text" placeholder="Focus me!" />
<button onClick={() => inputRef().focus()}>Focus Input</button>
</div>
);
};
6. Component Lifecycle
Managing component lifecycle with hooks:
import { render, setSignal, onMount, onUnmount } from "./core/core.js";
const LifecycleExample = () => {
const [isVisible, setIsVisible] = setSignal(true);
const ChildComponent = () => {
onMount(() => {
console.log("Component mounted");
});
onUnmount(() => {
console.log("Component will unmount");
});
return <div>Hello World</div>;
};
return (
<div>
<button onClick={() => setIsVisible(!isVisible())}>
{() => (isVisible() ? "Hide" : "Show")}
</button>
{() => isVisible() && <ChildComponent />}
</div>
);
};
7. List Rendering
Building a dynamic todo list:
import { render, setSignal } from "./core/core.js";
const TodoList = () => {
const [todos, setTodos] = setSignal([
{ id: 1, text: "Learn Olova.js" },
{ id: 2, text: "Build an app" },
]);
const [newTodo, setNewTodo] = setSignal("");
const addTodo = () => {
if (newTodo().trim()) {
setTodos([...todos(), { id: Date.now(), text: newTodo() }]);
setNewTodo("");
}
};
return (
<div>
<div>
<input
value={() => newTodo()}
onInput={(e) => setNewTodo(e.target.value)}
placeholder="New todo"
/>
<button onClick={addTodo}>Add Todo</button>
</div>
<ul>
{() =>
todos().map((todo) => (
<li key={todo.id}>
{todo.text}
<button
onClick={() =>
setTodos(todos().filter((t) => t.id !== todo.id))
}
>
Delete
</button>
</li>
))
}
</ul>
</div>
);
};
8. Conditional Rendering
Different patterns for conditional rendering:
import { render, setSignal } from "./core/core.js";
const Conditional = () => {
const [show, setShow] = setSignal(false);
const [theme, setTheme] = setSignal("light");
return (
<div>
<button onClick={() => setShow(!show())}>Toggle Content</button>
<button onClick={() => setTheme(theme() === "light" ? "dark" : "light")}>
Toggle Theme
</button>
{/* Simple conditional */}
{() => (show() ? <p>Content is shown</p> : <p>Content is hidden</p>)}
{/* Conditional with multiple elements */}
{() =>
theme() === "light" ? (
<div style={{ background: "white", color: "black" }}>Light Theme</div>
) : (
<div style={{ background: "black", color: "white" }}>Dark Theme</div>
)
}
{/* Conditional rendering with && operator */}
{() => show() && <p>This only shows when show is true</p>}
</div>
);
};
9. Components and Props
Creating and using reusable components with props:
import { render } from "./core/core.js";
// Button component with props
const Button = ({ text, onClick }) => {
return (
<button
onClick={onClick}
style={{
padding: "8px 16px",
borderRadius: "4px",
border: "none",
backgroundColor: "#0070f3",
color: "white",
cursor: "pointer",
}}
>
{text}
</button>
);
};
// Using the Button component
const App = () => {
return (
<div>
<h1>Component Example</h1>
<Button text="Click me!" onClick={() => alert("Button clicked!")} />
<Button
text="Another button"
onClick={() => console.log("Second button clicked")}
/>
</div>
);
};
This example shows:
- How to create a reusable component with props
- Passing different props to multiple instances
- Handling events through props
- Applying inline styles to components
π οΈ API Reference
Core Functions
Function | Description |
---|---|
setSignal(initialValue) |
Creates a reactive signal |
setEffect(effectFn) |
Creates an effect that tracks dependencies |
setMemo(computeFn) |
Creates a computed value |
setRef() |
Creates a ref for DOM elements |
render(component, root) |
Renders a component to the DOM |
onMount(callback) |
Runs when component mounts |
onUnmount(callback) |
Runs when component unmounts |
Fragment |
Wrapper for multiple elements |
html |
Internal function for DOM creation |
π€ Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
π License
MIT License
π¨βπ» Author
Nazmul Hossain
For more information and updates, please check back regularly as this framework
continues to evolve.
π‘ Pro Tip: Check out the
examples
directory in the source code for more
detailed examples and best practices!
Top comments (0)