signal 可以动态创建,而不是像 hook 一样被约束在函数顶层:

import { render } from "solid-js/web";
import { For, createSignal } from "solid-js";

const App = () => {
  const [todos, setTodos] = createSignal([])
  let input;
  let todoId = 0;

  const addTodo = (text) => {
	  // 可以动态创建
    const [completed, setCompleted] = createSignal(false); 
    setTodos([...todos(), { id: ++todoId, text, completed, setCompleted }]);
  }
  const toggleTodo = (id) => {
	  // 这样就不会导致整个 list 重新渲染,只会渲染 toggle 的部分
	  // 可以通过下面的 console.log 查看
    const todo = todos().find((t) => t.id === id);
    if (todo) todo.setCompleted(!todo.completed())
  }

  return (
    <>
      <div>
        <input ref={input} />
        <button
          onClick={(e) => {
            if (!input.value.trim()) return;
            addTodo(input.value);
            input.value = "";
          }}
        >
          Add Todo
        </button>
      </div>
      <For each={todos()}>
        {(todo) => {
          const { id, text } = todo;
          console.log(`Creating ${text}`)
          return <div>
            <input
              type="checkbox"
              checked={todo.completed()}
              onchange={[toggleTodo, id]}
            />
            <span
              style={{ "text-decoration": todo.completed() ? "line-through" : "none"}}
            >{text}</span>
          </div>
        }}
      </For>
    </>
  );
};

render(App, document.getElementById("app"));

当然也可以直接改 set 函数:

import { render, For } from "solid-js/web";
import { createStore, produce } from "solid-js/store";

const App = () => {
  let input;
  let todoId = 0;
  const [todos, setTodos] = createStore([]);
  const addTodo = (text) => {
    setTodos(
      produce((todos) => {
        todos.push({ id: ++todoId, text, completed: false });
      }),
    );
  };
  const toggleTodo = (id) => {
    setTodos(
      todo => todo.id === id,
      produce((todo) => (todo.completed = !todo.completed)),
    );
  };

  return (
    <>
      <div>
        <input ref={input} />
        <button
          onClick={(e) => {
            if (!input.value.trim()) return;
            addTodo(input.value);
            input.value = "";
          }}
        >
          Add Todo
        </button>
      </div>
      <For each={todos}>
        {(todo) => {
          const { id, text } = todo;
          console.log(`Creating ${text}`)
          return <div>
            <input
              type="checkbox"
              checked={todo.completed}
              onchange={[toggleTodo, id]}
            />
            <span
              style={{ "text-decoration": todo.completed ? "line-through" : "none" }}
            >{text}</span>
          </div>
        }}
      </For>
    </>
  );
};

render(App, document.getElementById("app"));