文档
Solid.js Hello World — 响应式计数器
目标
展示 Solid.js 核心概念:Signal、Effect、JSX 与控制流组件。Solid 的 JSX 语法类似 React 但行为完全不同——组件只执行一次,Signal 是真正的细粒度响应式。
完整代码
// src/index.jsx
/* @refresh reload */
import { render } from "solid-js/web";
import App from "./App";
render(() => <App />, document.getElementById("root"));
// src/App.jsx
import { createSignal, createEffect, onCleanup } from "solid-js";
import { Show, For, Switch, Match } from "solid-js";
export default function App() {
// createSignal 返回 [getter, setter]
const [count, setCount] = createSignal(0);
const [name, setName] = createSignal("朋友");
const [todos, setTodos] = createSignal(["学 Solid.js", "写项目"]);
const [newTodo, setNewTodo] = createSignal("");
// 自动追踪依赖——count() 变化时执行
createEffect(() => {
console.log(`计数变了:${count()}`);
document.title = `点击 ${count()} 次`;
});
// 定时器示例 + 清理
const timer = setInterval(() => {
// 不会重新执行组件!只更新这一个 signal
}, 1000);
onCleanup(() => clearInterval(timer));
const addTodo = () => {
if (newTodo().trim()) {
setTodos([...todos(), newTodo()]);
setNewTodo("");
}
};
return (
<main style={mainStyle}>
<h1>⚛️ Solid.js Demo</h1>
<p style={{ color: "#666" }}>
Solid 的组件只渲染一次,但 Signal 保持细粒度更新
</p>
{/* 双向绑定:value={name()} + onInput 更新 signal */}
<input
style={inputStyle}
value={name()}
onInput={(e) => setName(e.currentTarget.value)}
placeholder="你的名字..."
/>
<p>
你好,<strong>{name()}</strong>!
</p>
{/* 显示 signal 值——注意必须调用 () */}
<h2 style={{ fontSize: "3rem", textAlign: "center" }}>{count()}</h2>
<div style={{ textAlign: "center", margin: "16px 0" }}>
<button style={btnStyle} onClick={() => setCount((c) => c + 1)}>
+ 1
</button>
<button style={btnStyle} onClick={() => setCount((c) => c - 1)}>
- 1
</button>
<button style={{ ...btnStyle, background: "#64748b" }} onClick={() => setCount(0)}>
重置
</button>
</div>
{/* Show:条件渲染 */}
<Show when={count() >= 10}>
<div style={{ padding: 12, background: "#fef3c7", borderRadius: 8 }}>
🎉 达到 {count()} 次!
</div>
</Show>
{/* For:高效列表渲染 */}
<h3>📋 待办事项</h3>
<ul>
<For each={todos()}>
{(todo, index) => (
<li>
{index() + 1}. {todo}
<button
style={{ marginLeft: 8, color: "red", border: "none", cursor: "pointer" }}
onClick={() => setTodos(todos().filter((_, i) => i !== index()))}
>
✕
</button>
</li>
)}
</For>
</ul>
<div style={{ display: "flex", gap: 8 }}>
<input
style={{ flex: 1, ...inputStyle }}
value={newTodo()}
onInput={(e) => setNewTodo(e.currentTarget.value)}
placeholder="新待办..."
onKeyDown={(e) => e.key === "Enter" && addTodo()}
/>
<button style={btnStyle} onClick={addTodo}>
添加
</button>
</div>
{/* Switch/Match:多分支条件 */}
<div style={{ marginTop: 16, padding: 12, background: "#f0f0ff", borderRadius: 8 }}>
<Switch>
<Match when={count() === 0}>开始点击吧!</Match>
<Match when={count() < 5}>继续加油~</Match>
<Match when={count() < 10}>快突破 10 了!</Match>
<Match when={true}>🔥 你已经是大佬了</Match>
</Switch>
</div>
</main>
);
}
// 样式
const mainStyle = {
"max-width": "540px",
margin: "40px auto",
padding: "0 16px",
"font-family": "-apple-system, 'Microsoft YaHei', sans-serif",
};
const inputStyle = {
width: "100%",
padding: "10px",
border: "2px solid #e2e8f0",
"border-radius": "8px",
"font-size": "1rem",
"box-sizing": "border-box",
};
const btnStyle = {
padding: "10px 24px",
border: "none",
"border-radius": "8px",
"font-size": "1rem",
cursor: "pointer",
background: "#7c4dff",
color: "white",
};
<!-- index.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Solid.js App</title>
</head>
<body>
<div id="root"></div>
<script src="./src/index.jsx" type="module"></script>
</body>
</html>
运行步骤
npm install
npm run dev # Vite 开发服务器
预期输出
- 计数器实时更新,不依赖虚拟 DOM diff
- 输入框双向绑定 name signal
- 待办列表可增删
- Switch 组件根据计数显示不同消息
- 页面标题随计数变化(createEffect)