### 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 (
);
}
```
--------------------------------
### 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 (
{todos.map(todo => (
toggleTodo(todo.id)}
/>
{todo.text}
))}
);
}
```
```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 (
{(todo, index) =>
toggleTodo(todo.id)}
/>
{todo.text}
}
);
}
```
```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 (
{(todo) =>
toggleTodo(todo.id)}
/>
{todo.text}
}
);
}
```
```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 (
);
}
```
--------------------------------
### 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
;
}
```
--------------------------------
### 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 (
);
}
```
--------------------------------
### 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;
}
```