solid

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

SolidJS Core Knowledge

SolidJS 核心知识

Full Reference: See advanced.md for WebSocket primitive, context provider, chat component, room management, Socket.IO integration, and store patterns.
Deep Knowledge: Use
mcp__documentation__fetch_docs
with technology:
solid
for comprehensive documentation.
完整参考:有关WebSocket原语、上下文提供器、聊天组件、房间管理、Socket.IO集成和store模式的内容,请查看advanced.md
深度知识获取:使用
mcp__documentation__fetch_docs
工具,指定technology为
solid
以获取完整文档。

When NOT to Use This Skill

何时不使用此技能

Skip this skill when:
  • Working with React (use
    frontend-react
    - APIs are different)
  • Building Vue applications (use
    vue-composition
    )
  • Using Svelte (use
    svelte
    )
  • Working with Angular (use
    angular
    )
  • Need server-side only logic (no framework needed)
在以下场景跳过此技能:
  • 处理React相关内容时(请使用
    frontend-react
    - 两者API不同)
  • 构建Vue应用时(请使用
    vue-composition
  • 使用Svelte时(请使用
    svelte
  • 处理Angular相关内容时(请使用
    angular
  • 仅需要服务器端逻辑时(无需框架)

Component Structure

组件结构

tsx
import { createSignal, createEffect, createMemo } from 'solid-js';

interface Props {
  name: string;
  count?: number;
}

function Counter(props: Props) {
  const [localState, setLocalState] = createSignal('');
  const doubled = createMemo(() => (props.count ?? 0) * 2);

  createEffect(() => {
    console.log('Count changed:', props.count);
  });

  return (
    <div>
      <h1>Hello {props.name}</h1>
      <p>Doubled: {doubled()}</p>
      <button onClick={() => setLocalState('clicked')}>
        Click
      </button>
    </div>
  );
}
tsx
import { createSignal, createEffect, createMemo } from 'solid-js';

interface Props {
  name: string;
  count?: number;
}

function Counter(props: Props) {
  const [localState, setLocalState] = createSignal('');
  const doubled = createMemo(() => (props.count ?? 0) * 2);

  createEffect(() => {
    console.log('Count changed:', props.count);
  });

  return (
    <div>
      <h1>Hello {props.name}</h1>
      <p>Doubled: {doubled()}</p>
      <button onClick={() => setLocalState('clicked')}>
        Click
      </button>
    </div>
  );
}

Reactivity Primitives

响应式原语

APIPurpose
createSignal
Reactive state
createMemo
Cached computation
createEffect
Side effects
createResource
Async data fetching
createStore
Nested reactive objects
API用途
createSignal
响应式状态
createMemo
缓存计算结果
createEffect
副作用处理
createResource
异步数据获取
createStore
嵌套响应式对象

Key Differences from React

与React的主要区别

  • No Virtual DOM - fine-grained updates
  • Props are getters - access via
    props.name
  • No dependency arrays - auto-tracking
  • Components run once - not on every render
  • JSX compiles differently - expressions are reactive
  • 无虚拟DOM - 细粒度更新
  • Props是getter - 通过
    props.name
    访问
  • 无需依赖数组 - 自动跟踪依赖
  • 组件仅运行一次 - 并非每次渲染都运行
  • JSX编译方式不同 - 表达式具备响应式

Control Flow

控制流

tsx
import { Show, For, Switch, Match } from 'solid-js';

<Show when={isLoggedIn()} fallback={<Login />}>
  <Dashboard />
</Show>

<For each={items()}>{(item) => <Item data={item} />}</For>
tsx
import { Show, For, Switch, Match } from 'solid-js';

<Show when={isLoggedIn()} fallback={<Login />}>
  <Dashboard />
</Show>

<For each={items()}>{(item) => <Item data={item} />}</For>

Anti-Patterns

反模式

Anti-PatternWhy It's BadCorrect Approach
Destructuring propsLoses reactivityAccess via
props.name
Using React patternsDifferent paradigmUse Solid primitives
Not using
<Show>
component
Manual conditional logicUse
<Show when={}>
Recreating signals in componentsComponents run onceCreate outside or use stores
Using
innerHTML
without sanitization
XSS vulnerabilityUse DOMPurify
Not cleaning up in
onCleanup
Memory leaksAdd cleanup logic
反模式问题原因正确做法
解构props丢失响应式特性通过
props.name
访问
使用React模式范式不同使用Solid原语
不使用
<Show>
组件
手动编写条件逻辑使用
<Show when={}>
在组件内重复创建signals组件仅运行一次在组件外创建或使用stores
未经清理就使用
innerHTML
XSS漏洞使用DOMPurify
未在
onCleanup
中清理资源
内存泄漏添加清理逻辑

Quick Troubleshooting

快速故障排查

IssueLikely CauseSolution
Props not reactiveDestructured propsAccess via
props.name
Signal not updatingForgot to call setterUse
setCount(newValue)
Effect not runningNot tracking signalCall signal inside effect:
count()
Component re-runningTreating like ReactComponents run once, use signals
List not updatingUsing array methodsUse
produce()
from solid-js/store
Memory leaksNo cleanupUse
onCleanup()
问题可能原因解决方案
Props无响应式已解构props通过
props.name
访问
Signal未更新忘记调用setter使用
setCount(newValue)
Effect未触发未跟踪signal在effect内调用signal:
count()
组件重复运行按React方式处理组件仅运行一次,使用signals管理状态
列表未更新使用普通数组方法使用
solid-js/store
中的
produce()
内存泄漏未清理资源使用
onCleanup()

Production Readiness

生产就绪指南

Error Handling

错误处理

tsx
import { ErrorBoundary } from 'solid-js';

function App() {
  return (
    <ErrorBoundary
      fallback={(err, reset) => (
        <div>
          <p>Error: {err.message}</p>
          <button onClick={reset}>Retry</button>
        </div>
      )}
    >
      <MainContent />
    </ErrorBoundary>
  );
}
tsx
import { ErrorBoundary } from 'solid-js';

function App() {
  return (
    <ErrorBoundary
      fallback={(err, reset) => (
        <div>
          <p>Error: {err.message}</p>
          <button onClick={reset}>Retry</button>
        </div>
      )}
    >
      <MainContent />
    </ErrorBoundary>
  );
}

Performance

性能优化

tsx
// Lazy loading components
const HeavyComponent = lazy(() => import('./HeavyComponent'));

function App() {
  return (
    <Suspense fallback={<Loading />}>
      <HeavyComponent />
    </Suspense>
  );
}

// Batch updates (rarely needed)
import { batch } from 'solid-js';

batch(() => {
  setCount(count() + 1);
  setName('New Name');
});
tsx
// Lazy loading components
const HeavyComponent = lazy(() => import('./HeavyComponent'));

function App() {
  return (
    <Suspense fallback={<Loading />}>
      <HeavyComponent />
    </Suspense>
  );
}

// Batch updates (rarely needed)
import { batch } from 'solid-js';

batch(() => {
  setCount(count() + 1);
  setName('New Name');
});

Store Patterns

Store模式

tsx
import { createStore, produce } from 'solid-js/store';

const [state, setState] = createStore({
  users: [] as User[],
  filters: { active: true },
});

// Immutable-style updates with produce
function addUser(user: User) {
  setState(produce((s) => {
    s.users.push(user);
  }));
}

// Path-based updates
setState('users', (users) => [...users, newUser]);
setState('filters', 'active', false);
tsx
import { createStore, produce } from 'solid-js/store';

const [state, setState] = createStore({
  users: [] as User[],
  filters: { active: true },
});

// Immutable-style updates with produce
function addUser(user: User) {
  setState(produce((s) => {
    s.users.push(user);
  }));
}

// Path-based updates
setState('users', (users) => [...users, newUser]);
setState('filters', 'active', false);

Testing

测试

tsx
import { render, screen } from '@solidjs/testing-library';
import userEvent from '@testing-library/user-event';
import Counter from './Counter';

describe('Counter', () => {
  it('increments on click', async () => {
    const user = userEvent.setup();
    render(() => <Counter initial={0} />);

    const button = screen.getByRole('button');
    await user.click(button);

    expect(screen.getByText('Count: 1')).toBeInTheDocument();
  });
});
tsx
import { render, screen } from '@solidjs/testing-library';
import userEvent from '@testing-library/user-event';
import Counter from './Counter';

describe('Counter', () => {
  it('increments on click', async () => {
    const user = userEvent.setup();
    render(() => <Counter initial={0} />);

    const button = screen.getByRole('button');
    await user.click(button);

    expect(screen.getByText('Count: 1')).toBeInTheDocument();
  });
});

Security

安全

tsx
// innerHTML - only with trusted content
<div innerHTML={sanitizedHtml} />

// Prefer text content
<div>{userInput}</div> // Safe - auto-escaped

// XSS prevention
import DOMPurify from 'dompurify';

function SafeHtml(props: { html: string }) {
  const clean = () => DOMPurify.sanitize(props.html);
  return <div innerHTML={clean()} />;
}
tsx
// innerHTML - only with trusted content
<div innerHTML={sanitizedHtml} />

// Prefer text content
<div>{userInput}</div> // Safe - auto-escaped

// XSS prevention
import DOMPurify from 'dompurify';

function SafeHtml(props: { html: string }) {
  const clean = () => DOMPurify.sanitize(props.html);
  return <div innerHTML={clean()} />;
}

Monitoring Metrics

监控指标

MetricTarget
Bundle size< 30KB
First Contentful Paint< 1s
Time to Interactive< 1.5s
Memory usageStable
指标目标值
包体积< 30KB
首次内容绘制< 1秒
可交互时间< 1.5秒
内存占用稳定

Checklist

检查清单

  • ErrorBoundary for error handling
  • Suspense for async operations
  • Lazy loading for code splitting
  • createStore for complex state
  • Virtual lists for large data
  • No innerHTML with user input
  • Testing with @solidjs/testing-library
  • SSR with SolidStart
  • Fine-grained updates (no unnecessary re-renders)
  • Bundle analysis
  • 使用ErrorBoundary处理错误
  • 对异步操作使用Suspense
  • 懒加载组件以拆分代码
  • 使用createStore管理复杂状态
  • 对大数据使用虚拟列表
  • 不使用innerHTML处理用户输入
  • 使用@solidjs/testing-library进行测试
  • 使用SolidStart实现SSR
  • 细粒度更新(无不必要的重渲染)
  • 包体积分析

Reference Documentation

参考文档

Deep Knowledge: Use
mcp__documentation__fetch_docs
with technology:
solid
for comprehensive documentation.
  • Primitives Cheatsheet
  • React Migration Guide
深度知识获取:使用
mcp__documentation__fetch_docs
工具,指定technology为
solid
以获取完整文档。
  • 原语速查表
  • React迁移指南