Skip to content

Quick Start Guide

Welcome to React Signify! In ~10 minutes, you'll learn the library and build a working todo app.

What is React Signify?

React Signify is a simple state management library for React with just two main methods:

  • use() - Read state in components
  • set() - Update state from anywhere
bash
npm install react-signify

Mini Project: Todo App

We'll build a simple todo app step by step to learn React Signify.

Step 1: Create Project Setup

bash
npx create-react-app my-todo-app --template typescript
cd my-todo-app
npm install react-signify

Step 2: Create State (src/store.ts)

First, create your global state:

typescript
import { signify } from "react-signify";

// Todo type
export interface Todo {
  id: number;
  text: string;
  completed: boolean;
}

// Global state - accessible from anywhere
export const sTodos = signify<Todo[]>([]);
export const sInputText = signify("");

What happened? Created two pieces of global state that any component can read and update.

Step 3: Create Todo List (src/TodoList.tsx)

tsx
import React from "react";
import { sTodos } from "./store";

export function TodoList() {
  const todoList = sTodos.use(); // Read state - auto re-renders when changed

  const toggle = (id: number) => {
    sTodos.set((pre) => {
      const todo = pre.value.find((todo) => todo.id === id);
      if (todo) {
        todo.completed = !todo.completed; // Direct mutation - allowed!
      }
    });
  };

  const remove = (id: number) => {
    sTodos.set((pre) => {
      const index = pre.value.findIndex((todo) => todo.id === id);
      if (index !== -1) {
        pre.value.splice(index, 1); // Direct removal from array!
      }
    });
  };

  return (
    <div>
      {todoList.map((todo) => (
        <div
          key={todo.id}
          style={{ padding: "8px", borderBottom: "1px solid #eee" }}
        >
          <input
            type="checkbox"
            checked={todo.completed}
            onChange={() => toggle(todo.id)}
          />
          <span
            style={{ textDecoration: todo.completed ? "line-through" : "none" }}
          >
            {todo.text}
          </span>
          <button
            onClick={() => remove(todo.id)}
            style={{ marginLeft: "10px" }}
          >
            Delete
          </button>
        </div>
      ))}
    </div>
  );
}

What happened? Component reads sTodos with use(), updates with set(). Notice we can mutate objects and arrays directly - no immutable updates needed!

Step 4: Create Add Todo (src/AddTodo.tsx)

tsx
import React from "react";
import { sTodos, sInputText } from "./store";

export function AddTodo() {
  const text = sInputText.use(); // Read input state

  const add = () => {
    if (text.trim()) {
      sTodos.set((pre) => {
        pre.value.push({ id: Date.now(), text, completed: false }); // Direct push!
      });
      sInputText.set(""); // Clear input
    }
  };

  return (
    <div style={{ marginBottom: "20px" }}>
      <input
        value={text}
        onChange={(e) => sInputText.set(e.target.value)} // Update input state
        placeholder="Add todo..."
        style={{ padding: "8px", marginRight: "8px" }}
      />
      <button onClick={add} style={{ padding: "8px" }}>
        Add
      </button>
    </div>
  );
}

What happened? Input field is controlled by global state. Notice we can push() directly to the array - no need for spread operator!

Step 5: Main App (src/App.tsx)

tsx
import React from "react";
import { AddTodo } from "./AddTodo";
import { TodoList } from "./TodoList";

function App() {
  return (
    <div style={{ maxWidth: "400px", margin: "50px auto", padding: "20px" }}>
      <h1>Todo App</h1>
      <AddTodo />
      <TodoList />
    </div>
  );
}

export default App;

Step 6: Run It

bash
npm start

Done! You now have a working todo app using React Signify.

What You Just Learned

Core Concepts:

  1. signify(value) - Creates global state
  2. state.use() - Reads state in components (auto re-renders)
  3. state.set(newValue) - Updates state directly
  4. state.set(pre => { pre.value = newValue }) - Updates with callback
  5. Direct mutation allowed - You can mutate pre.value directly: change properties, push to arrays, etc!

Key Benefits:

  • ✅ No providers or context
  • ✅ Global state accessible anywhere
  • ✅ Automatic re-renders
  • ✅ TypeScript support
  • ✅ Minimal boilerplate

Quick Examples

typescript
// Create state
const sCount = signify(0);
// Read in component
const sCountValue = sCount.use();

// Update directly
sCount.set(5);

// Update with callback
sCount.set((pre) => {
  pre.value = pre.value + 1;
});

const sUser = signify({ name: "John", age: 25 });

// Direct mutation (objects/arrays) - React Signify allows this!
sUser.set((pre) => {
  pre.value.age = 26; // Direct property change
});

// Or replace entire value
sUser.set((pre) => {
  pre.value = { name: "Jane", age: 30 }; // Replace entire object
});

const sTodos = signify([{ id: 1, text: "Learn React" }]);

sTodos.set((pre) => {
  pre.value.push({ id: 2, text: "Build app" }); // Direct push to array!
  pre.value.splice(0, 1); // Direct removal from array!
});

Next Steps

Happy coding! 🚀

Released under the MIT License.