Hello World - 响应式图书收藏

知识库
知识库文档
/tech-stacks/solidjs/examples/Hello World - 响应式图书收藏.md

文档

Solid.js 响应式图书收藏

目标

用 Solid.js 实现图书收藏列表,展示 createSignal 响应式状态、createEffect 副作用和 For 控制流。

完整代码

src/index.jsx

import { render } from 'solid-js/web';
import App from './App';

render(() => <App />, document.getElementById('root'));

src/App.jsx

import { createSignal, createEffect, For, Show } from 'solid-js';
import styles from './App.module.css';

const INITIAL_BOOKS = [
  { id: 1, title: '深入理解计算机系统', author: 'Randal E. Bryant', year: 2016, read: true },
  { id: 2, title: '代码整洁之道', author: 'Robert C. Martin', year: 2010, read: false },
  { id: 3, title: '设计模式', author: 'GoF', year: 1994, read: true },
];

export default function App() {
  const [books, setBooks] = createSignal(INITIAL_BOOKS);
  const [newBook, setNewBook] = createSignal({ title: '', author: '', year: '' });
  const [search, setSearch] = createSignal('');

  // 派生状态:搜索结果
  const filteredBooks = () => {
    const term = search().toLowerCase();
    if (!term) return books();
    return books().filter(b =>
      b.title.toLowerCase().includes(term) ||
      b.author.toLowerCase().includes(term)
    );
  };

  // 副作用:统计已读数量
  createEffect(() => {
    const readCount = books().filter(b => b.read).length;
    console.log(`已读: ${readCount}/${books().length}`);
  });

  const addBook = (e) => {
    e.preventDefault();
    const b = newBook();
    if (!b.title || !b.author) return;
    setBooks(prev => [...prev, { ...b, id: Date.now(), read: false, year: Number(b.year) || 2024 }]);
    setNewBook({ title: '', author: '', year: '' });
  };

  const toggleRead = (id) => {
    setBooks(prev => prev.map(b => b.id === id ? { ...b, read: !b.read } : b));
  };

  const removeBook = (id) => {
    setBooks(prev => prev.filter(b => b.id !== id));
  };

  return (
    <div class={styles.app}>
      <h1>📚 图书收藏</h1>

      <input
        type="text"
        placeholder="搜索书名或作者..."
        value={search()}
        onInput={(e) => setSearch(e.target.value)}
        class={styles.search}
      />

      {/* 添加表单 */}
      <form onSubmit={addBook} class={styles.form}>
        <input
          placeholder="书名" value={newBook().title}
          onInput={(e) => setNewBook(p => ({ ...p, title: e.target.value }))}
        />
        <input
          placeholder="作者" value={newBook().author}
          onInput={(e) => setNewBook(p => ({ ...p, author: e.target.value }))}
        />
        <input
          placeholder="年份" type="number" value={newBook().year}
          onInput={(e) => setNewBook(p => ({ ...p, year: e.target.value }))}
        />
        <button type="submit">➕ 添加</button>
      </form>

      {/* 图书列表 */}
      <div class={styles.list}>
        <Show when={filteredBooks().length > 0} fallback={<p style="color:#999">没有匹配的图书</p>}>
          <For each={filteredBooks()}>
            {(book) => (
              <div class={`${styles.card} ${book.read ? styles.read : ''}`}>
                <div class={styles.info}>
                  <strong>{book.title}</strong>
                  <small>{book.author} · {book.year}</small>
                </div>
                <div class={styles.actions}>
                  <button onClick={() => toggleRead(book.id)}>
                    {book.read ? '✅ 已读' : '📖 标记已读'}
                  </button>
                  <button onClick={() => removeBook(book.id)} class={styles.del}>🗑️</button>
                </div>
              </div>
            )}
          </For>
        </Show>
      </div>

      <p class={styles.stats}>
        共 {books().length} 本 · 已读 {books().filter(b => b.read).length} 本
      </p>
    </div>
  );
}

运行步骤

npx degit solidjs/templates/js solid-books
cd solid-books
npm install
# 替换 src/App.jsx
npm run dev

预期输出

  • 展示 3 本预置图书,2 本标记已读(绿色)
  • 搜索框实时过滤图书
  • 添加新书后列表自动响应式更新
  • 控制台输出已读统计

信息

路径
/tech-stacks/solidjs/examples/Hello World - 响应式图书收藏.md
更新时间
2026/5/30