Hello World - 响应式计数器

知识库
知识库文档
/tech-stacks/solidjs/examples/Hello World - 响应式计数器.md

文档

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)

信息

路径
/tech-stacks/solidjs/examples/Hello World - 响应式计数器.md
更新时间
2026/5/31