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"));