Use the /collab command on Discord to gain access to the OneJS private repo. The repo offers early access to the latest features and fixes that may not yet be available on the Asset Store. An early preview of OneJS V2 is available on branch onejs-v2. It brings major performance improvements, zero-allocation interop, and a new esbuild workflow.
Menu

ToDo List with Signals

Port of the original Preact/signals ToDo example Playground

memo logic added by @cucumba :

abc

import { h, render } from "preact"
import { memo } from "preact/compat"
import { signal, computed } from "preact/signals"

const todos = signal([
    { text: "Write my first post", completed: true },
    { text: "Buy new groceries", completed: false },
    { text: "Walk the dog", completed: false },
]);

const completedCount = computed(() => {
    return todos.value.filter(todo => todo.completed).length
});

const newItem = signal("")

function addTodo() {
    todos.value = [...todos.value, { text: newItem.value, completed: false }]
    newItem.value = "" // Reset input value on add
}

function removeTodo(index) {
    todos.value.splice(index, 1)
    todos.value = [...todos.value]
}

function areEqual(prevProps, nextProps) {
    if (prevProps.todo.completed !== nextProps.todo.completed) {
        return false
    }

    if (prevProps.todo.text !== nextProps.todo.text) {
        return false
    }

    if (prevProps.index !== nextProps.index) {
        return false
    }
    return true
}

const TodoItem = memo(({ todo, index }) => {
    // log(todo.text); // should only be called for new/changed elements
    const onCheckboxChange = (event) => {
        const newTodo = { ...todo, completed: event.target.value }
        todos.value = [
            ...todos.value.slice(0, index),
            newTodo,
            ...todos.value.slice(index + 1),
        ]
    }
    return (
        <div class="flex-row items-center mb-2">
            <toggle onValueChanged={onCheckboxChange} value={todo.completed} />
            {todo.completed ? <s>{todo.text}</s> : todo.text}{" "}
            <button onClick={() => removeTodo(index)} text="X" />
        </div>
    )
}, areEqual)

function TodoList() {
    const onInput = event => (newItem.value = event.target.value);
    const elements = todos.value.map((todo, index) => (
        <TodoItem key={index} todo={todo} index={index} />
    ))
    return (
        <div class="p-2">
            <div class="flex-row">
                <textfield class="grow" text={newItem.value} onInput={onInput} />
                <button class="shrink" onClick={addTodo} text="Add" />
            </div>
            <div class="p-2">
                <ul>{elements}</ul>
                <p>{`Completed count: ${completedCount.value}`}</p>
            </div>
        </div>
    )
}

render(<TodoList />, document.body)