乐闻世界logo
搜索文章和话题

面试题手册

SolidJS Router 如何使用?有哪些高级特性?

SolidJS Router 提供了强大的客户端路由功能:基本使用:import { Router, Route, Routes } from '@solidjs/router';function App() { return ( <Router> <Routes> <Route path="/" component={Home} /> <Route path="/about" component={About} /> <Route path="/users/:id" component={User} /> </Routes> </Router> );}路由参数:function User() { const params = useParams(); const userId = () => params.id; // 响应式访问 return <div>User ID: {userId()}</div>;}导航:import { useNavigate, Link, A } from '@solidjs/router';function Navigation() { const navigate = useNavigate(); const handleClick = () => { navigate('/about'); // 编程式导航 }; return ( <nav> <Link href="/">Home</Link> {/* 使用 Link 组件 */} <A href="/about">About</A> {/* 使用 A 组件(更轻量) */} <button onClick={handleClick}>Go to About</button> </nav> );}嵌套路由:function App() { return ( <Router> <Routes> <Route path="/" component={Layout}> <Route path="/" component={Home} /> <Route path="/about" component={About} /> </Route> </Routes> </Router> );}function Layout(props) { return ( <div> <Header /> {props.children} <Footer /> </div> );}路由守卫:function ProtectedRoute(props) { const isAuthenticated = createMemo(() => checkAuth()); return ( <Show when={isAuthenticated()}> {props.children} </Show> );}数据预加载:const [data] = createResource(fetchData);function DataRoute() { return ( <Show when={!data.loading} fallback={<Loading />}> <div>{data().content}</div> </Show> );}
阅读 0·2月21日 15:24

SolidJS 和 React 有什么区别?如何选择适合的框架?

SolidJS 和 React 都是现代前端框架,但设计理念和技术实现有显著差异:核心架构对比:| 特性 | React | SolidJS ||------|-------|---------|| 渲染方式 | 虚拟 DOM + 重新渲染 | 细粒度响应式 + 直接 DOM 更新 || 组件执行 | 每次状态变化重新执行 | 只执行一次 || 状态管理 | useState, useReducer | createSignal, createStore || 副作用处理 | useEffect(需声明依赖) | createEffect(自动追踪) || 派生状态 | useMemo(需声明依赖) | createMemo(自动追踪) || 列表渲染 | map + key | For, Index 组件 || 条件渲染 | 三元运算符, &&, || | Show, Switch 组件 |代码对比示例:// Reactfunction Counter() { const [count, setCount] = useState(0); useEffect(() => { document.title = `Count: ${count}`; }, [count]); const doubled = useMemo(() => count * 2, [count]); return ( <div> <p>Count: {count}</p> <p>Doubled: {doubled}</p> <button onClick={() => setCount(c => c + 1)}>+</button> </div> );}// SolidJSfunction Counter() { const [count, setCount] = createSignal(0); createEffect(() => { document.title = `Count: ${count()}`; }); const doubled = createMemo(() => count() * 2); return ( <div> <p>Count: {count()}</p> <p>Doubled: {doubled()}</p> <button onClick={() => setCount(c => c + 1)}>+</button> </div> );}性能对比:SolidJS 在大型列表渲染中性能更优SolidJS 内存占用更小React 生态系统更成熟React 学习资源更丰富适用场景:选择 React:团队熟悉 React、需要丰富生态、大型企业应用选择 SolidJS:追求极致性能、需要细粒度更新、响应式优先的应用迁移建议:React 开发者可以快速上手 SolidJS概念相似但实现方式不同需要改变思维方式(从重新渲染到响应式更新)
阅读 0·2月21日 15:23

SolidJS 有哪些性能优化技巧?如何避免常见的性能陷阱?

SolidJS 提供了多种性能优化技巧,可以显著提升应用性能:使用 createMemo 缓存计算结果:// 不好的做法 - 每次渲染都重新计算function Component() { const [items, setItems] = createSignal([]); const total = () => items().reduce((sum, item) => sum + item.price, 0); return <div>Total: {total()}</div>;}// 好的做法 - 使用 createMemo 缓存function Component() { const [items, setItems] = createSignal([]); const total = createMemo(() => items().reduce((sum, item) => sum + item.price, 0)); return <div>Total: {total()}</div>;}批量更新:import { batch } from 'solid-js';// 不好的做法 - 多次触发更新function updateMultiple() { setName('John'); setAge(25); setEmail('john@example.com');}// 好的做法 - 使用 batch 批量更新function updateMultiple() { batch(() => { setName('John'); setAge(25); setEmail('john@example.com'); });}使用 Index 优化列表渲染:// For - 使用对象作为 key(适合动态列表)<For each={items()} fallback={<div>No items</div>}> {(item) => <div>{item.name}</div>}</For>// Index - 使用索引作为 key(性能更好,适合静态列表)<Index each={items()}> {(item, index) => <div>{item().name}</div>}</Index>懒加载组件:import { lazy } from 'solid-js';const HeavyComponent = lazy(() => import('./HeavyComponent'));function App() { return ( <Suspense fallback={<Loading />}> <HeavyComponent /> </Suspense> );}避免不必要的响应式:// 不好的做法 - 创建不必要的 signalfunction Component() { const [count, setCount] = createSignal(0); const doubled = createSignal(() => count() * 2); // 不需要 signal return <div>{doubled()}</div>;}// 好的做法 - 使用普通函数function Component() { const [count, setCount] = createSignal(0); const doubled = () => count() * 2; return <div>{doubled()}</div>;}使用 untrack 避免追踪:import { untrack } from 'solid-js';createEffect(() => { const value = untrack(() => someSignal()); console.log(value); // 不会建立依赖关系});性能监控:import { devtools } from 'solid-js/dev';devtools; // 启用开发工具
阅读 0·2月21日 15:23

SolidJS 中的控制流组件有哪些?如何使用 Show、For、Switch 等?

SolidJS 提供了多种控制流组件,用于条件渲染和列表渲染:条件渲染:// Show - 条件渲染(类似 React 的条件渲染)<Show when={isLoggedIn()} fallback={<Login />}> <Dashboard /></Show>// Switch - 多条件分支<Switch fallback={<NotFound />}> <Match when={status() === 'loading'}> <Loading /> </Match> <Match when={status() === 'success'}> <Success /> </Match> <Match when={status() === 'error'}> <Error /> </Match></Switch>列表渲染:// For - 列表渲染(推荐使用)<For each={items()}> {(item, index) => ( <div> {index()}: {item.name} </div> )}</For>// Index - 使用索引作为 key(性能更好)<Index each={items()}> {(item, index) => ( <div> {index}: {item().name} </div> )}</Index>动态组件:// Dynamic - 动态组件渲染<Dynamic component={currentComponent()} props={props} />// Portal - 传送门到其他 DOM 节点<Portal mount={document.getElementById('modal-root')}> <Modal /></Portal>Suspense - 异步加载:<Suspense fallback={<Loading />}> <AsyncComponent /></Suspense>// 嵌套 Suspense<Suspense fallback={<Skeleton />}> <Suspense fallback={<LoadingAvatar />}> <UserAvatar /> </Suspense> <Suspense fallback={<LoadingPosts />}> <UserPosts /> </Suspense></Suspense>ErrorBoundary - 错误边界:<ErrorBoundary fallback={(err) => <ErrorPage error={err} />}> <Component /></ErrorBoundary>最佳实践:使用 For 而不是 map 进行列表渲染使用 Index 当列表项顺序不变时使用 Show 进行简单条件判断使用 Switch 处理多条件分支使用 Suspense 处理异步组件
阅读 0·2月21日 15:23

SolidJS 如何与 TypeScript 配合使用?有哪些类型定义最佳实践?

SolidJS 提供了完善的 TypeScript 支持和类型系统:基本类型定义:import { createSignal, createEffect } from 'solid-js';// 定义 signal 类型const [count, setCount] = createSignal<number>(0);const [user, setUser] = createSignal<User | null>(null);// 定义 effectcreateEffect(() => { const value = count(); // value 自动推断为 number console.log(value);});组件类型定义:// 函数组件interface Props { title: string; count: number; onIncrement?: () => void;}function Counter(props: Props) { return ( <div> <h1>{props.title}</h1> <p>Count: {props.count}</p> <button onClick={props.onIncrement}>+</button> </div> );}// 使用 JSX.IntrinsicElements 扩展原生元素类型declare module 'solid-js' { namespace JSX { interface IntrinsicElements { 'my-custom-element': { value: string; onChange: (value: string) => void; }; } }}Store 类型定义:import { createStore } from 'solid-js/store';interface AppState { user: { name: string; age: number; email: string; }; items: Array<{ id: number; name: string; }>;}const [state, setState] = createStore<AppState>({ user: { name: '', age: 0, email: '' }, items: []});// 类型安全的更新setState('user', 'name', 'John'); // ✅ 正确setState('user', 'invalid', 'value'); // ❌ 类型错误Resource 类型定义:import { createResource } from 'solid-js';interface User { id: number; name: string; email: string;}const [user] = createResource<User>(fetchUser);const userValue = user(); // User | undefined// 使用泛型定义返回类型const [data] = createResource<User[], Error>(fetchUsers, { initialValue: []});Context 类型定义:import { createContext, useContext } from 'solid-js';interface ThemeContextType { theme: 'light' | 'dark'; toggleTheme: () => void;}const ThemeContext = createContext<ThemeContextType>();function useTheme() { const context = useContext(ThemeContext); if (!context) { throw new Error('useTheme must be used within ThemeProvider'); } return context;}类型工具:// 使用 utility typestype PartialState = Partial<AppState>;type RequiredState = Required<AppState>;type ReadonlyState = Readonly<AppState>;// 条件类型type SignalType<T> = T extends (...args: any[]) => any ? ReturnType<T> : T;最佳实践:为所有组件定义 Props 接口使用泛型定义 signal 和 store 类型为 context 定义明确的类型使用 utility types 简化类型定义启用严格模式检查
阅读 0·2月21日 15:23

SolidJS 如何进行单元测试和集成测试?有哪些测试工具推荐?

SolidJS 提供了强大的测试工具和方法来测试组件和响应式逻辑:测试工具:import { render, screen, fireEvent, waitFor } from '@solidjs/testing-library';import { describe, it, expect } from 'vitest';describe('Counter Component', () => { it('renders initial count', () => { render(() => <Counter />); expect(screen.getByText('Count: 0')).toBeInTheDocument(); }); it('increments count when button clicked', async () => { render(() => <Counter />); const button = screen.getByText('+'); fireEvent.click(button); await waitFor(() => { expect(screen.getByText('Count: 1')).toBeInTheDocument(); }); });});测试响应式逻辑:import { createSignal, createEffect } from 'solid-js';import { createRoot } from 'solid-js';describe('Reactive Logic', () => { it('tracks signal changes', () => { createRoot((dispose) => { const [count, setCount] = createSignal(0); let effectCallCount = 0; createEffect(() => { effectCallCount++; count(); }); expect(effectCallCount).toBe(1); setCount(1); expect(effectCallCount).toBe(2); dispose(); }); });});测试异步操作:import { createResource } from 'solid-js';describe('Async Operations', () => { it('handles loading state', async () => { const fetchMock = vi.fn(() => new Promise(resolve => setTimeout(() => resolve({ data: 'test' }), 100)) ); const [data] = createResource(fetchMock); expect(data.loading).toBe(true); await waitFor(() => expect(data.loading).toBe(false)); expect(data()).toEqual({ data: 'test' }); });});测试用户交互:describe('User Interactions', () => { it('handles form submission', () => { render(() => <LoginForm />); const input = screen.getByLabelText('Email'); const button = screen.getByText('Submit'); fireEvent.input(input, { target: { value: 'test@example.com' } }); fireEvent.click(button); expect(screen.getByText('Submitted: test@example.com')).toBeInTheDocument(); });});测试路由:import { Router } from '@solidjs/router';describe('Routing', () => { it('renders correct component for route', () => { render(() => ( <Router> <Routes> <Route path="/" component={Home} /> <Route path="/about" component={About} /> </Routes> </Router> )); expect(screen.getByText('Home Page')).toBeInTheDocument(); });});最佳实践:使用 @solidjs/testing-library 进行组件测试使用 createRoot 包装测试以自动清理测试用户行为而非实现细节使用 waitFor 处理异步操作Mock 外部依赖和 API 调用保持测试独立和可重复
阅读 0·2月21日 15:23

SolidJS 如何实现服务端渲染(SSR)?有哪些渲染模式?

SolidJS 支持服务端渲染(SSR),提供多种渲染模式:基本 SSR 设置:// entry-server.jsximport { renderToString } from 'solid-js/web';import App from './App';export function render(url) { return renderToString(() => <App url={url} />);}// entry-client.jsximport { hydrate } from 'solid-js/web';import App from './App';hydrate(() => <App />, document);渲染模式:静态生成(SSG):import { renderToStringAsync } from 'solid-js/web';export async function getStaticPaths() { return ['/about', '/contact'];}export default async function Page({ params }) { return renderToStringAsync(() => <Component />);}服务端渲染(SSR):import { StartServer, createHandler } from '@solidjs/start/server';export default createHandler(() => ( <StartServer document={({ assets, children }) => ( <html> <head>{assets}</head> <body>{children}</body> </html> )} />));流式渲染:import { renderToStream } from 'solid-js/web';app.get('*', async (req, res) => { const stream = renderToStream(() => <App />); stream.pipe(res);});数据获取:// 使用 createResource 处理异步数据const [data] = createResource(fetchData, { initialValue: null, deferStream: true // 支持流式传输});// 服务端数据预取export async function getData() { return await fetchData();}同构应用:// 在服务端和客户端都能运行的代码function Component() { const isServer = useIsServer(); return ( <div> {isServer() ? 'Server' : 'Client'} </div> );}性能优化:使用 deferStream 延迟加载预取关键数据优化 hydration 过程使用 Suspense 边界
阅读 0·2月21日 15:22