# React to SolidJS Conversion Patterns This guide documents common patterns for converting React code to SolidJS for this migration. ## Table of Contents - [State Management](#state-management) - [Effects](#effects) - [Refs](#refs) - [Routing](#routing) - [Conditional Rendering](#conditional-rendering) - [Lists](#lists) - [Forms](#forms) - [Event Handlers](#event-handlers) ## State Management ### React (useState) ```tsx import { useState } from "react"; const [count, setCount] = useState(0); const [user, setUser] = useState(null); // Update setCount(count + 1); setCount(prev => prev + 1); setUser({ ...user, name: "John" }); ``` ### Solid (createSignal) ```tsx import { createSignal } from "solid-js"; const [count, setCount] = createSignal(0); const [user, setUser] = createSignal(null); // Update - note the function call to read value setCount(count() + 1); setCount(prev => prev + 1); setUser({ ...user(), name: "John" }); // ⚠️ Important: Always call the signal to read its value console.log(count()); // ✅ Correct console.log(count); // ❌ Wrong - this is the function itself ``` ## Effects ### React (useEffect) ```tsx import { useEffect } from "react"; // Run once on mount useEffect(() => { console.log("Mounted"); return () => { console.log("Cleanup"); }; }, []); // Run when dependency changes useEffect(() => { console.log(count); }, [count]); ``` ### Solid (createEffect / onMount / onCleanup) ```tsx import { createEffect, onMount, onCleanup } from "solid-js"; // Run once on mount onMount(() => { console.log("Mounted"); }); // Cleanup onCleanup(() => { console.log("Cleanup"); }); // Run when dependency changes (automatic tracking) createEffect(() => { console.log(count()); // Automatically tracks count signal }); // ⚠️ Important: Effects automatically track any signal reads // No dependency array needed! ``` ## Refs ### React (useRef) ```tsx import { useRef } from "react"; const inputRef = useRef(null); // Access inputRef.current?.focus(); // In JSX ``` ### Solid (let binding or signal) ```tsx // Method 1: Direct binding (preferred for simple cases) let inputRef: HTMLInputElement | undefined; // Access inputRef?.focus(); // In JSX // Method 2: Using a signal (for reactive refs) import { createSignal } from "solid-js"; const [inputRef, setInputRef] = createSignal(); // Access inputRef()?.focus(); // In JSX ``` ## Routing ### React (Next.js) ```tsx import Link from "next/link"; import { useRouter } from "next/navigation"; // Link component About // Programmatic navigation const router = useRouter(); router.push("/dashboard"); router.back(); router.refresh(); ``` ### Solid (SolidStart) ```tsx import { A, useNavigate } from "@solidjs/router"; // Link component About // Programmatic navigation const navigate = useNavigate(); navigate("/dashboard"); navigate(-1); // Go back // Note: No refresh() - Solid is reactive by default ``` ## Conditional Rendering ### React ```tsx // Using && operator {isLoggedIn && } // Using ternary {isLoggedIn ? : } // Using if statement if (loading) return ; return ; ``` ### Solid ```tsx import { Show } from "solid-js"; // Using Show component (recommended) // With fallback }> // ⚠️ Important: Can still use && and ternary, but Show is more efficient // because it doesn't recreate the DOM on every change // Early return still works if (loading()) return ; return ; ``` ## Lists ### React ```tsx // Using map {users.map(user => (
{user.name}
))} // With index {users.map((user, index) => (
{user.name}
))} ``` ### Solid ```tsx import { For, Index } from "solid-js"; // Using For (when items have stable keys) {(user) =>
{user.name}
}
// With index {(user, index) =>
{index()} - {user.name}
}
// Using Index (when items have no stable identity, keyed by index) {(user, index) =>
{index} - {user().name}
}
// ⚠️ Key differences: // - For: Better when items have stable identity (keyed by reference) // - Index: Better when items change frequently (keyed by index) // - Note the () on user in Index component ``` ## Forms ### React ```tsx import { useState } from "react"; const [email, setEmail] = useState(""); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); console.log(email); };
setEmail(e.target.value)} />
``` ### Solid ```tsx import { createSignal } from "solid-js"; const [email, setEmail] = createSignal(""); const handleSubmit = (e: Event) => { e.preventDefault(); console.log(email()); };
setEmail(e.currentTarget.value)} />
// ⚠️ Important differences: // - Use onInput instead of onChange for real-time updates // - onChange fires on blur in Solid // - Use e.currentTarget instead of e.target for type safety ``` ## Event Handlers ### React ```tsx // Inline