### React Component Wrapping with forEach Source: https://context7.com/blankeos/react-to-solid-llms/llms.txt Demonstrates a simple approach in React to wrap a component multiple times using `useState` and `forEach`. This method is less efficient for dynamic nesting as it creates new JSX elements in each iteration. ```tsx import { useState } from 'react'; function PageRenderer({ children }) { const [layouts, setLayouts] = useState([RootLayout, DashboardLayout]); let page = children; layouts.forEach((Layout) => { page = {page}; }); return page; } ``` -------------------------------- ### SolidJS createStore for Syncing External Stores (Observer Pattern) Source: https://context7.com/blankeos/react-to-solid-llms/llms.txt This snippet demonstrates how to synchronize an external vanilla JavaScript store (ToastManager) with a SolidJS `createStore` using the observer pattern. It subscribes to changes in the external store and updates the Solid store reactively. ```tsx import { createStore, reconcile } from 'solid-js/store'; import { onMount, onCleanup } from 'solid-js'; import { For } from 'solid-js'; // External vanilla JS store class ToastManager { listeners = []; subscribe(fn) { this.listeners.push(fn); return () => { this.listeners = this.listeners.filter(l => l !== fn); }; } notify(toast) { this.listeners.forEach(fn => fn(toast)); } } const toastManager = new ToastManager(); function ToastContainer() { const [state, setState] = createStore({ toasts: [] }); onMount(() => { const unsubscribe = toastManager.subscribe((toast) => { if (toast.dismiss) { setState('toasts', t => t.filter(item => item.id !== toast.id)); return; } const exists = state.toasts.find(t => t.id === toast.id); if (exists) { // Update existing toast setState('toasts', t => t.id === toast.id, reconcile(toast)); } else { // Add new toast setState('toasts', toasts => [toast, ...toasts]); } }); onCleanup(unsubscribe); }); return ( {(toast) =>
{toast.message}
}
); } ``` -------------------------------- ### SolidJS Dynamic Layout Rendering with Switch/Match Source: https://context7.com/blankeos/react-to-solid-llms/llms.txt Presents an alternative method for dynamic layout rendering in SolidJS using `Switch` and `Match` for recursive component wrapping. This pattern allows for conditional rendering and dynamic updates to the layout structure, managed via `createStore`. ```tsx import { Switch, Match, JSX } from 'solid-js'; import { createStore } from 'solid-js/store'; const WrapWithLayouts = (props: { layouts: any[], children: JSX.Element, index: number }) => { return ( {(() => { const CurrentLayout = props.layouts[props.index]; return ( {props.children} ); })()} ); }; function DynamicLayoutPage() { const [layouts, setLayouts] = createStore([ RootLayout, DashboardLayout ]); // Can dynamically update layouts const addLayout = () => { setLayouts([...layouts, SettingsLayout]); }; return ( <>
Page Content
); } ``` -------------------------------- ### Solid vs React: Callback Stability and Memoization Source: https://context7.com/blankeos/react-to-solid-llms/llms.txt Illustrates how Solid's component model naturally provides stable functions, making `useCallback` unnecessary for preventing re-creation across renders, unlike in React. It also shows how `createMemo` is used in Solid for expensive derived computations. ```tsx // React: Functions recreated on every render function SearchBox() { const [query, setQuery] = useState(''); const [results, setResults] = useState([]); // ❌ New function instance on every render const handleChange = (e) => { setQuery(e.target.value); }; // ✅ Stable function reference const handleChangeStable = useCallback((e) => { setQuery(e.target.value); }, []); // Empty deps since setQuery is stable const handleSearch = useCallback(async () => { const data = await fetch(`/api?q=${query}`); setResults(await data.json()); }, [query]); // Re-created when query changes return (
); } ``` ```tsx // Solid: Functions are stable by default function SearchBox() { const [query, setQuery] = createSignal(''); const [results, setResults] = createSignal([]); // ✅ Created once, naturally stable const handleChange = (e) => { setQuery(e.target.value); }; // ✅ Created once, accesses current signal value when called const handleSearch = async () => { const data = await fetch(`/api?q=${query()}`); setResults(await data.json()); }; return (
); } // When you DO need memoization: expensive derived values import { createMemo } from 'solid-js'; function DataProcessor() { const [data, setData] = createSignal([/* large array */]); // ✅ Memoize expensive computation, not the function const processedData = createMemo(() => { return data().map(/* expensive transform */).filter(/* complex logic */); }); return
{processedData().length} items processed
; } ``` -------------------------------- ### SolidJS createStore for Complex State Management Source: https://context7.com/blankeos/react-to-solid-llms/llms.txt This snippet shows how to manage complex state in SolidJS using `createStore`. It replaces the reducer pattern with action functions that directly mutate the store using Immer-like proxy-based updates, offering fine-grained reactivity. ```tsx import { createStore } from 'solid-js/store'; import { For } from 'solid-js'; function App() { const [state, setState] = createStore({ user: { name: 'John', age: 30 }, todos: [ { id: 1, text: 'Task 1', completed: false } ], settings: { theme: 'dark', notifications: true } }); // Define actions as functions that mutate the store const actions = { updateUser: (updates) => { setState('user', updates); }, toggleTodo: (id) => { setState('todos', t => t.id === id, 'completed', c => !c); }, addTodo: (text) => { setState('todos', todos => [...todos, { id: Date.now(), text, completed: false }]); }, updateSettings: (key, value) => { setState('settings', key, value); } }; return (

{state.user.name}

{(todo) =>
actions.toggleTodo(todo.id)}> {todo.text} - {todo.completed ? '✓' : '○'}
}
); } ``` -------------------------------- ### Solid vs React: Props Destructuring and Reactivity Source: https://context7.com/blankeos/react-to-solid-llms/llms.txt Demonstrates the correct way to access props in Solid.js components to maintain reactivity, contrasting it with React where destructuring is safe. Incorrect destructuring in Solid freezes prop values. ```tsx // React: Props are just values, destructuring is safe function Child({ count, name }) { return
{count} - {name}
; } // Solid: WRONG - Destructuring kills reactivity function Child(props) { const { count, name } = props; // ❌ Values frozen at creation return
{count} - {name}
; // Will never update } // Solid: CORRECT - Access props dynamically function Child(props) { return
{props.count} - {props.name}
; // ✅ Updates work } ``` -------------------------------- ### Solid vs React: Reactive Media Query Hooks Source: https://context7.com/blankeos/react-to-solid-llms/llms.txt Compares a React `useMediaQuery` hook that takes a string query with a Solid.js `useMediaQuery` hook that accepts a reactive accessor (string or function) for dynamic query updates. The Solid version utilizes `createSignal` and `createEffect` for reactivity. ```tsx // React hook: Takes string value function useMediaQuery(query: string): boolean { const [matches, setMatches] = useState(false); useEffect(() => { const mq = window.matchMedia(query); setMatches(mq.matches); const listener = (e) => setMatches(e.matches); mq.addEventListener('change', listener); return () => mq.removeEventListener('change', listener); }, [query]); return matches; } // Usage: Hook re-runs when query changes const isDesktop = useMediaQuery('(min-width: 768px)'); ``` ```tsx // Solid hook: Takes Accessor for reactive updates import { Accessor, createSignal, createEffect, onCleanup } from 'solid-js'; function useMediaQuery(query: Accessor | string) { const getQuery = () => typeof query === 'function' ? query() : query; const [matches, setMatches] = createSignal(false); createEffect(() => { const q = getQuery(); // Tracks signal if provided const mq = window.matchMedia(q); setMatches(mq.matches); const listener = (e) => setMatches(e.matches); mq.addEventListener('change', listener); onCleanup(() => mq.removeEventListener('change', listener)); }); return matches; } // Usage: Pass signal for reactive updates const [query, setQuery] = createSignal('(min-width: 768px)'); const isDesktop = useMediaQuery(query); // Later: setQuery('(min-width: 1024px)') automatically updates isDesktop ``` -------------------------------- ### Implementing Signal-Based Refs for Click Outside Handling in SolidJS Source: https://context7.com/blankeos/react-to-solid-llms/llms.txt Shows how to create a custom hook `useClickOutside` in SolidJS that uses `createSignal` for managing a ref and `createEffect` to attach a global event listener. This allows detecting clicks outside of a referenced element for callback execution. ```tsx import { createSignal, createEffect, onCleanup } from 'solid-js'; function useClickOutside(handler) { const [ref, setRef] = createSignal(); createEffect(() => { const listener = (event) => { if (ref() && !ref().contains(event.target)) { handler(); } }; document.addEventListener('mousedown', listener); onCleanup(() => document.removeEventListener('mousedown', listener)); }); return setRef; // Use as ref={setRef} } ``` -------------------------------- ### Measure DOM Element Height in React and SolidJS Source: https://context7.com/blankeos/react-to-solid-llms/llms.txt Compares how to measure the height of a DOM element using `useRef` and `useLayoutEffect` in React, and plain variables with `createEffect` in SolidJS. Both examples attach a ref to a div and update its height measurement. ```tsx import { useRef, useLayoutEffect, useState } from 'react'; function MeasureElement() { const divRef = useRef(null); const [height, setHeight] = useState(0); useLayoutEffect(() => { if (divRef.current) { const { height } = divRef.current.getBoundingClientRect(); setHeight(height); } }, []); return (
Content to measure

Height: {height}px

); } ``` ```tsx import { createSignal, createEffect } from 'solid-js'; function MeasureElement() { let divRef; const [height, setHeight] = createSignal(0); createEffect(() => { if (divRef) { const rect = divRef.getBoundingClientRect(); setHeight(rect.height); } }); return (
Content to measure

Height: {height()}px

); } ``` -------------------------------- ### Forwarding and Merging Refs in a Custom Input Component Source: https://context7.com/blankeos/react-to-solid-llms/llms.txt Demonstrates how to forward a ref from a parent component to an internal DOM element within a custom component. This allows the parent to access and manipulate the child's DOM node, such as calling focus(). ```tsx function CustomInput(props) { let internalRef; const handleRef = (el) => { internalRef = el; // Keep internal reference props.ref?.(el); // Forward to parent }; const focus = () => internalRef?.focus(); return ; } ``` -------------------------------- ### SolidJS Dynamic Layout Rendering with createComponent Source: https://context7.com/blankeos/react-to-solid-llms/llms.txt Implements dynamic component composition in SolidJS using functional recursion with `createComponent`. This approach ensures lazy evaluation of children, preventing unnecessary re-renders when layouts are nested or updated. It utilizes `createStore` for managing layout configurations. ```tsx import { createComponent, JSX } from 'solid-js'; import { createStore } from 'solid-js/store'; function PageRenderer(props: { children: JSX.Element }) { const [layouts, setLayouts] = createStore([ RootLayout, DashboardLayout, SettingsLayout ]); function renderLayouts(index: number = 0): JSX.Element { const layout = layouts[index]; // Base case: no more layouts if (!layout) return props.children; // Recursive case: wrap and continue return createComponent(layout, { get children(): JSX.Element { return renderLayouts(index + 1); } }); } return <>{renderLayouts(0)}; } ``` -------------------------------- ### Force Attribute Binding on Web Components using SolidJS Source: https://context7.com/blankeos/react-to-solid-llms/llms.txt Illustrates how to bind attributes to a custom Web Component (`my-element`) using SolidJS's `attr:` prefix. This method ensures that attributes like `data-index`, `aria-label`, and `disabled` are correctly set based on reactive signals. ```tsx import { createSignal } from 'solid-js'; function WebComponentExample() { const [index, setIndex] = createSignal(0); const [active, setActive] = createSignal(true); return ( ); } ``` -------------------------------- ### List Rendering and Reconciliation: React vs. SolidJS Source: https://context7.com/blankeos/react-to-solid-llms/llms.txt Compares list rendering in React using map with keys and SolidJS using the For component. Highlights how Solid's createStore with reconcile enables fine-grained updates, preventing full re-renders by tracking data identity, unlike Solid's default For component behavior when not using keys or React's map which can be less performant for large lists. ```tsx // React: map with key prop function TodoList() { const [todos, setTodos] = useState([ { id: 1, text: 'Learn React', completed: false }, { id: 2, text: 'Build app', completed: false } ]); const toggleTodo = (id) => { setTodos(todos.map(todo => todo.id === id ? { ...todo, completed: !todo.completed } : todo )); }; return ( ); } ``` ```tsx // Solid: For component without keys import { createSignal, For } from 'solid-js'; function TodoList() { const [todos, setTodos] = createSignal([ { id: 1, text: 'Learn Solid', completed: false }, { id: 2, text: 'Build app', completed: false } ]); const toggleTodo = (id) => { // ⚠️ Creates new array - all DOM nodes recreated! setTodos(todos().map(todo => todo.id === id ? { ...todo, completed: !todo.completed } : todo )); }; return ( ); } ``` ```tsx // Solid: createStore for fine-grained list updates import { createStore } from 'solid-js/store'; import { For } from 'solid-js'; function TodoListOptimized() { const [state, setState] = createStore({ todos: [ { id: 1, text: 'Learn Solid', completed: false }, { id: 2, text: 'Build app', completed: false } ] }); const toggleTodo = (id) => { // ✅ Only updates the specific todo's completed property setState('todos', todo => todo.id === id, 'completed', c => !c); }; const addTodo = (text) => { // ✅ Only appends new item, existing DOM preserved setState('todos', todos => [...todos, { id: Date.now(), text, completed: false }]); }; return ( ); } ``` ```tsx // Advanced: reconcile for bulk API updates import { createStore, reconcile } from 'solid-js/store'; function LiveFeed() { const [state, setState] = createStore({ items: [] }); const refreshFromAPI = async () => { const response = await fetch('/api/items'); const newItems = await response.json(); // ✅ Matches by reference/id, preserves unchanged items setState('items', reconcile(newItems, { key: 'id' })); }; return {/* ... */}; } ``` -------------------------------- ### Effects and Lifecycle: React useEffect to SolidJS createEffect Source: https://context7.com/blankeos/react-to-solid-llms/llms.txt Demonstrates the conversion of React's useEffect hook to SolidJS's createEffect. Solid's createEffect automatically tracks reactive dependencies, eliminating the need for manual dependency arrays. Cleanup is handled with onCleanup, and accessing previous values is integrated into the effect's signature. ```tsx import { useEffect, useState } from 'react'; function Logger() { const [count, setCount] = useState(0); const [name, setName] = useState('John'); useEffect(() => { console.log(`Count changed to ${count}`); const timer = setInterval(() => { console.log('Interval tick'); }, 1000); return () => clearInterval(timer); }, [count]); // Must list dependencies or get stale closures return ; } ``` ```tsx import { createSignal, createEffect, onCleanup } from 'solid-js'; function Logger() { const [count, setCount] = createSignal(0); const [name, setName] = createSignal('John'); createEffect(() => { console.log(`Count changed to ${count()}`); // Automatically tracks count(), not name() const timer = setInterval(() => { console.log('Interval tick'); }, 1000); onCleanup(() => clearInterval(timer)); }); return ; } ``` ```tsx // Accessing previous values with effect arguments import { createEffect } from 'solid-js'; function PreviousValueTracker() { const [count, setCount] = createSignal(0); createEffect((prevCount) => { const current = count(); if (prevCount !== undefined) { console.log(`Changed from ${prevCount} to ${current}`); } return current; // Becomes prevCount in next run }, 0); // Initial value return ; } ``` ```tsx // Explicit dependencies with 'on' helper import { on, createEffect } from 'solid-js'; function ExplicitTracking() { const [count, setCount] = createSignal(0); const [enabled, setEnabled] = createSignal(true); createEffect(on(count, (currentCount) => { // Only tracks count, not enabled if (enabled()) { // Reading enabled() here doesn't track it console.log('Count:', currentCount); } })); } ``` -------------------------------- ### Convert React useCounter Hook to SolidJS useCounter Source: https://context7.com/blankeos/react-to-solid-llms/llms.txt This snippet shows the conversion of a React 'useCounter' hook to SolidJS. It highlights the replacement of 'useState' with 'createSignal', the removal of 'useCallback', and the simplified dependency management in SolidJS. The 'clamp' utility function remains similar across both implementations. ```tsx // React: useCounter with callbacks and deps import { useState, useCallback } from 'react'; interface UseCounterOptions { min?: number; max?: number; } function clamp(value: number, min?: number, max?: number): number { if (min !== undefined && value < min) return min; if (max !== undefined && value > max) return max; return value; } export function useCounter( initialValue = 0, options?: UseCounterOptions ): [number, UseCounterHandlers] { const { min, max } = options || {}; const [count, setCount] = useState(clamp(initialValue, min, max)); const increment = useCallback( () => setCount(current => clamp(current + 1, min, max)), [min, max] ); const decrement = useCallback( () => setCount(current => clamp(current - 1, min, max)), [min, max] ); const set = useCallback( (value: number) => setCount(clamp(value, min, max)), [min, max] ); const reset = useCallback( () => setCount(clamp(initialValue, min, max)), [initialValue, min, max] ); return [count, { increment, decrement, set, reset }]; } // Usage function CounterDemo() { const [count, { increment, decrement, set, reset }] = useCounter(0, { min: 0, max: 10 }); return (

Count: {count}

); } ``` ```tsx // Solid: useCounter simplified import { createSignal } from 'solid-js'; function clamp(value: number, min?: number, max?: number): number { if (min !== undefined && value < min) return min; if (max !== undefined && value > max) return max; return value; } export function useCounter( initialValue = 0, options: Partial<{ min: number; max: number }> = {} ) { const [count, setCount] = createSignal( clamp(initialValue, options.min, options.max) ); // No useCallback needed - functions are stable const increment = () => setCount(c => clamp(c + 1, options.min, options.max)); const decrement = () => setCount(c => clamp(c - 1, options.min, options.max)); const set = (value: number) => setCount(clamp(value, options.min, options.max)); const reset = () => setCount(clamp(initialValue, options.min, options.max)); return [count, { increment, decrement, set, reset }] as const; } // Usage function CounterDemo() { const [count, { increment, decrement, set, reset }] = useCounter(0, { min: 0, max: 10 }); return (

Count: {count()}

); } ``` -------------------------------- ### Non-Reactive State: React useRef vs. SolidJS Variables Source: https://context7.com/blankeos/react-to-solid-llms/llms.txt Demonstrates managing non-reactive state in SolidJS using plain variables (let/const) as an alternative to React's useRef. This approach is suitable for values like timers, flags, or previous states that do not require re-renders upon change and leverage Solid's component execution model where variables persist across renders. ```tsx // React: useRef to persist values across renders function Timer() { const intervalRef = useRef(null); const countRef = useRef(0); useEffect(() => { intervalRef.current = setInterval(() => { countRef.current += 1; console.log('Tick:', countRef.current); }, 1000); return () => clearInterval(intervalRef.current); }, []); return
Check console
; } ``` ```tsx // Solid: Plain variables import { onMount, onCleanup } from 'solid-js'; function Timer() { let intervalId; let count = 0; onMount(() => { intervalId = setInterval(() => { count += 1; console.log('Tick:', count); }, 1000); }); onCleanup(() => { clearInterval(intervalId); }); return
Check console
; } ``` ```tsx // Debounce pattern with plain variables function SearchInput() { let timeoutId; const [query, setQuery] = createSignal(''); const handleInput = (e) => { clearTimeout(timeoutId); timeoutId = setTimeout(() => { setQuery(e.target.value); }, 300); }; return ; } ``` ```tsx // Tracking previous scroll position function ScrollTracker() { let lastScrollTop = 0; const handleScroll = (e) => { const scrollTop = e.target.scrollTop; const direction = scrollTop > lastScrollTop ? 'down' : 'up'; console.log('Scrolling', direction); lastScrollTop = scrollTop; }; return
Content
; } ``` -------------------------------- ### Solid: Using Accessors for Reactive Hooks Source: https://github.com/blankeos/react-to-solid-llms/blob/main/concepts/props-and-accessors.md When porting hooks from React to Solid, Solid hooks often accept Accessors (functions that return a value) instead of direct values. This allows the hook to re-run when the underlying signal changes. This example demonstrates passing a signal (Accessor) to a Solid hook. ```tsx // Solid Hook // useMediaQuery(query: Accessor | string) const [query, setQuery] = createSignal('(min-width: 768px)'); const matches = useMediaQuery(query); // Pass the signal! ``` -------------------------------- ### State Management: React useState to SolidJS createSignal Source: https://context7.com/blankeos/react-to-solid-llms/llms.txt Compares React's useState hook with SolidJS's createSignal for managing component state. Solid's signals offer fine-grained reactivity, updating only dependent UI parts without re-rendering the entire component. This snippet also shows how to create global signals in Solid. ```tsx import { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); return (

Count: {count}

); } ``` ```tsx import { createSignal } from 'solid-js'; function Counter() { const [count, setCount] = createSignal(0); return (

Count: {count()}

); } ``` ```tsx // Solid signals can be global without extra libraries const [globalCount, setGlobalCount] = createSignal(0); export function useGlobalCounter() { return [globalCount, setGlobalCount]; } ``` -------------------------------- ### SolidJS: Persist Values Across Component Lifecycle with `let` Source: https://github.com/blankeos/react-to-solid-llms/blob/main/concepts/non-reactive-state.md SolidJS components execute their setup function only once. Therefore, standard JavaScript `let` variables declared within the component scope persist for the entire lifecycle of the component. This makes them suitable for managing values like interval IDs without needing a special hook. ```tsx import { onMount, onCleanup } from 'solid-js'; function Timer() { let intervalId; onMount(() => { intervalId = setInterval(() => { // Timer logic }, 1000); }); onCleanup(() => { clearInterval(intervalId); }); return
Timer component
; } ``` -------------------------------- ### Implement useMediaQuery Hook in SolidJS Source: https://github.com/blankeos/react-to-solid-llms/blob/main/examples/subscriptions.md The SolidJS implementation of the useMediaQuery hook accepts a query as an Accessor, enabling dynamic query updates. It utilizes `createSignal` for state management and `createEffect` for reactive updates, returning the match signal itself for consumer tracking. ```typescript import { Accessor, createEffect, createSignal } from 'solid-js'; export function useMediaQuery( query: Accessor, // Accepts an Accessor! // ... options ) { const [matches, setMatches] = createSignal(getInitialValue(query())); let queryRef: MediaQueryList; createEffect(() => { // Calling query() tracks it. // If the signal passed to query updates, this effect re-runs. if ('matchMedia' in window) { queryRef = window.matchMedia(query()); setMatches(queryRef.matches); const listener = event => setMatches(event.matches); queryRef.addEventListener('change', listener); // Cleanup happens automatically before next run or unmount onCleanup(() => queryRef.removeEventListener('change', listener)); } }); return matches; // Return the signal (Accessor), not the value! ``` -------------------------------- ### React: Passing Simple Values as Props Source: https://github.com/blankeos/react-to-solid-llms/blob/main/concepts/props-and-accessors.md In React, props are passed as simple values. When the parent re-renders, the child component re-renders with the updated value. This example shows a basic child component receiving a 'count' prop. ```tsx // React function Child({ count }) { // 'count' is a number. // When parent re-renders, Child re-renders with new number. return
{count}
; } ``` -------------------------------- ### Implement useMediaQuery Hook in React Source: https://github.com/blankeos/react-to-solid-llms/blob/main/examples/subscriptions.md The React implementation of the useMediaQuery hook listens to changes in a media query string and returns a boolean indicating whether the query matches. It uses `useState` for the match state and `useEffect` to set up and clean up the event listener. ```typescript export function useMediaQuery( query: string, // ... options ): boolean { const [matches, setMatches] = useState(getInitialValue(query)); useEffect(() => { const mediaQuery = window.matchMedia(query); setMatches(mediaQuery.matches); const listener = (event) => setMatches(event.matches); mediaQuery.addEventListener('change', listener); return () => mediaQuery.removeEventListener('change', listener); }, [query]); // Re-runs if query string changes return matches; } ``` -------------------------------- ### React useReducer for Complex State Management Source: https://context7.com/blankeos/react-to-solid-llms/llms.txt This snippet illustrates the traditional approach to managing complex, nested state in React using the `useReducer` hook. It defines an initial state and a reducer function to handle different action types for updating the state. ```tsx import { useReducer } from 'react'; const initialState = { user: { name: 'John', age: 30 }, todos: [ { id: 1, text: 'Task 1', completed: false } ], settings: { theme: 'dark', notifications: true } }; function reducer(state, action) { switch (action.type) { case 'UPDATE_USER': return { ...state, user: { ...state.user, ...action.payload } }; case 'TOGGLE_TODO': return { ...state, todos: state.todos.map(todo => todo.id === action.id ? { ...todo, completed: !todo.completed } : todo ) }; case 'ADD_TODO': return { ...state, todos: [...state.todos, action.todo] }; default: return state; } } function App() { const [state, dispatch] = useReducer(reducer, initialState); return (
); } ``` -------------------------------- ### Solid.js Syncing External State with createStore and reconcile Source: https://github.com/blankeos/react-to-solid-llms/blob/main/concepts/stores-vs-reducers.md Illustrates syncing an external vanilla JavaScript observable store with a Solid.js `createStore`. It uses `reconcile` for efficient updates and demonstrates handling add/update and dismiss events for a toast manager. ```tsx import { createStore, reconcile } from 'solid-js/store'; import { ToastState } from './external-state'; // The vanilla JS observer const [state, setState] = createStore({ toasts: [] }); onMount(() => { // Subscribe to the external vanilla JS store const unsubscribe = ToastState.subscribe((toast) => { // 1. Handle specialized events (like dismiss) if (toast.dismiss) { setState("toasts", (t) => t.filter(item => item.id !== toast.id)); return; } // 2. Handle Add/Update // If the toast already exists, update it deeply. // If not, prepend it. const exists = state.toasts.find(t => t.id === toast.id); if (exists) { // Solid's reconcile or path syntax handles the merge seamlessly setState("toasts", (t) => t.id === toast.id, reconcile(toast)); } else { setState("toasts", (t) => [toast, ...t]); } }); onCleanup(unsubscribe); }); ``` -------------------------------- ### Solid.js Replacing useReducer with Store Actions Source: https://github.com/blankeos/react-to-solid-llms/blob/main/concepts/stores-vs-reducers.md Demonstrates how to replace the boilerplate of `useReducer`'s switch statements in Solid.js by defining direct mutation functions on the store. This achieves separation of concerns with less code. ```tsx const [state, _setState] = createStore({ count: 0 }); const actions = { increment: () => _setState("count", (c) => c + 1), decrement: () => _setState("count", (c) => c - 1), }; ``` -------------------------------- ### Callback Memoization in React vs. Solid Source: https://github.com/blankeos/react-to-solid-llms/blob/main/concepts/callbacks-and-stability.md Compares the pattern for memoizing callbacks in React using `useCallback` with its dependency array, versus the SolidJS approach where no explicit memoization hook is needed due to stable function references. ```tsx const handleChange = useCallback((event) => { setValue(event.target.value); }, []); // Dependency array needed ``` ```tsx // No hook needed. Accessing state (signals) works because // signals are stable references with dynamic values. const handleChange = (event) => { setValue(event.target.value); }; ``` -------------------------------- ### React useState Initialization Source: https://github.com/blankeos/react-to-solid-llms/blob/main/concepts/state-vs-signals.md Demonstrates how to initialize state in React using the useState hook. The initial value is directly assigned to the state variable. ```tsx const [count, setCount] = useState(0); // count is the value (0) ``` -------------------------------- ### Debounced Value Hook: React vs. SolidJS Source: https://context7.com/blankeos/react-to-solid-llms/llms.txt This snippet demonstrates the implementation of a `useDebouncedValue` hook in both React and SolidJS. It shows how to manage debounced state updates, converting `useRef` in React to plain variables in SolidJS for better performance. The hook accepts a value and a wait time, returning the debounced value and a cancel function. ```typescript import { useState, useEffect, useRef } from 'react'; export function useDebouncedValue( value: T, wait: number, options = { leading: false } ): [T, () => void] { const [_value, setValue] = useState(value); const timeoutRef = useRef(null); const cooldownRef = useRef(false); const mountedRef = useRef(false); useEffect(() => { mountedRef.current = true; return () => { mountedRef.current = false; }; }, []); const cancel = () => { if (timeoutRef.current) { window.clearTimeout(timeoutRef.current); } }; useEffect(() => { if (mountedRef.current) { if (!cooldownRef.current && options.leading) { cooldownRef.current = true; setValue(value); } else { cancel(); timeoutRef.current = window.setTimeout(() => { cooldownRef.current = false; setValue(value); }, wait); } } }, [value, options.leading, wait]); return [_value, cancel]; } // Usage function SearchWithDebounce() { const [query, setQuery] = useState(''); const [debouncedQuery, cancel] = useDebouncedValue(query, 500); useEffect(() => { if (debouncedQuery) { fetch(`/api/search?q=${debouncedQuery}`) .then(r => r.json()) .then(results => console.log(results)); } }, [debouncedQuery]); return (
setQuery(e.target.value)} />
); } ``` ```typescript import { Accessor, createEffect, createSignal, on } from 'solid-js'; export function useDebouncedValue( value: Accessor, wait: number, options = { leading: false } ) { const [_value, setValue] = createSignal(value()); // Plain variables instead of useRef let timeoutRef: number | null = null; let cooldownRef = false; const cancel = () => { if (timeoutRef) window.clearTimeout(timeoutRef); }; // Explicit tracking with 'on' createEffect( on(value, () => { if (!cooldownRef && options.leading) { cooldownRef = true; setValue(() => value()); } else { cancel(); timeoutRef = window.setTimeout(() => { cooldownRef = false; setValue(() => value()); }, wait); } }) ); return [_value, cancel] as const; } // Usage function SearchWithDebounce() { const [query, setQuery] = createSignal(''); const [debouncedQuery, cancel] = useDebouncedValue(query, 500); createEffect(() => { const q = debouncedQuery(); if (q) { fetch(`/api/search?q=${q}`) .then(r => r.json()) .then(results => console.log(results)); } }); return (
setQuery(e.currentTarget.value)} />
); } ``` -------------------------------- ### Implement useClickOutside Hook in React Source: https://github.com/blankeos/react-to-solid-llms/blob/main/examples/event-listeners.md The React implementation of the useClickOutside hook uses `useRef` to manage the DOM element reference and `useEffect` for event listener setup and cleanup. It attaches event listeners to the document and invokes a callback when a click occurs outside the referenced element. Dependencies for the effect include the ref, callback, and optional nodes. ```typescript import { useEffect, useRef } from 'react'; export function useClickOutside( callback: (event: EventType) => void, events?: string[] | null, nodes?: (HTMLElement | null)[] ) { const ref = useRef(null); const eventsList = events || DEFAULT_EVENTS; useEffect(() => { const listener = (event: Event) => { // ... logic ... if (ref.current && !ref.current.contains(target as Node)) { callback(event as EventType); } }; eventsList.forEach((fn) => document.addEventListener(fn, listener)); // Cleanup returned from effect return () => { eventsList.forEach((fn) => document.removeEventListener(fn, listener)); }; }, [ref, callback, nodes]); // Dependencies trigger re-bind return ref; } ``` -------------------------------- ### Solid Composable Refs via Callback Functions Source: https://github.com/blankeos/react-to-solid-llms/blob/main/concepts/refs-and-dom.md Solid's ref system, using callback functions, allows for easy composition. A single ref callback can manage both internal state and forward the ref to a parent. ```tsx let internalRef; const handleRef = (el) => { internalRef = el; // Keep a local reference if needed // props.ref?.(el); // Forward to parent if parent passed a ref callback }; // Usage in JSX:
; // Access internalRef directly within the component or use the forwarded ref ``` -------------------------------- ### Solid: Implementing a Hook with Accessor Input Source: https://github.com/blankeos/react-to-solid-llms/blob/main/concepts/props-and-accessors.md This TypeScript code demonstrates a Solid hook implementation that accepts either a direct string value or an Accessor. It uses `createEffect` to track changes by calling the Accessor if provided, ensuring reactivity. ```typescript import { Accessor, createEffect } from 'solid-js'; // Solid implementation function useSomething(value: Accessor | string) { const getValue = () => typeof value === 'function' ? (value as Accessor)() : value; createEffect(() => { console.log(getValue()); // Tracks changes! }); } ``` -------------------------------- ### Solid.js Nested State Update with createStore Source: https://github.com/blankeos/react-to-solid-llms/blob/main/concepts/stores-vs-reducers.md Shows how to update nested state in Solid.js using `createStore`. The proxy-based API allows for direct-like mutation syntax, simplifying updates and leveraging fine-grained reactivity. ```tsx import { createStore } from "solid-js/store"; const [state, setState] = createStore({ todos: [{ id: 1, text: "Learn Solid", completed: false }], }); // "Mutate" deeply using path syntax const toggleTodo = (id) => { setState( "todos", (todo) => todo.id === id, "completed", (c) => !c, ); }; ``` -------------------------------- ### SolidJS createSignal Initialization Source: https://github.com/blankeos/react-to-solid-llms/blob/main/concepts/state-vs-signals.md Illustrates state initialization in SolidJS using createSignal. The state is accessed via a getter function, and it can live outside the component render cycle. ```tsx const [count, setCount] = createSignal(0); // count is a GETTER function (() => 0) ``` -------------------------------- ### SolidJS: Switch/Match Recursion for Dynamic Wrapping Source: https://github.com/blankeos/react-to-solid-llms/blob/main/concepts/functional-recursion.md Simulates dynamic component wrapping and recursion in SolidJS using the `Switch` and `Match` components. This provides a way to handle conditional rendering that mimics early returns. ```typescript import { Switch, Match, JSX } from "solid-js"; import { createStore } from "solid-js/store"; // Helper component that handles wrapping using Switch/Match const WrapWithLayouts = (props: { layouts: any[], children: JSX.Element, index: number }) => { return ( {(() => { const CurrentComponent = props.layouts[props.index]; return ( {props.children} ); })()} ); }; function PageRenderer() { const [layouts, setLayouts] = createStore([ RootLayout, DashboardLayout, ]); return I am page } ``` -------------------------------- ### DOM Measurement with Solid's createEffect Source: https://github.com/blankeos/react-to-solid-llms/blob/main/concepts/refs-and-dom.md Solid's `createEffect` runs after the DOM update paint, which is generally sufficient for most DOM measurement needs. It accesses the ref directly. ```tsx import { createEffect, createSignal } from 'solid-js'; let ref; const [measurement, setMeasurement] = createSignal(0); createEffect(() => { // This runs after the DOM has updated if (ref) { const { height } = ref.getBoundingClientRect(); setMeasurement(height); } }); // ... render the element with ref={ref} ``` -------------------------------- ### React State Management with useState and useReducer Source: https://github.com/blankeos/react-to-solid-llms/blob/main/concepts/stores-vs-reducers.md Demonstrates common patterns in React for managing nested state using `useState` with shallow copying or `useReducer`. This approach can become verbose and error-prone with complex state structures. ```tsx const [state, dispatch] = useReducer(reducer, { count: 0, user: { name: "John" }, }); // or setUser({ ...user, name: "Jane" }); ``` -------------------------------- ### React: Dynamic Component Wrapping with Looping Source: https://github.com/blankeos/react-to-solid-llms/blob/main/concepts/functional-recursion.md Demonstrates how to dynamically wrap children components in React by iterating through a list of layouts. This works due to React's component re-composition model. ```tsx import React, { useState, PropsWithChildren } from 'react'; function PageRenderer(props: PropsWithChildren) { const [layouts, setLayouts] = useState([RootLayout, DashboardLayout]); let page = props.children; layouts.forEach((Layout) => { page = {page}; // You just need to keep wrapping page with the Layout. }); return page; } ```