### Install @rbxts/react and @rbxts/react-roblox Source: https://github.com/littensy/rbxts-react/blob/main/README.md Install the alpha versions of @rbxts/react and @rbxts/react-roblox using npm, yarn, or pnpm. ```sh npm install @rbxts/react @rbxts/react-roblox yarn add @rbxts/react @rbxts/react-roblox pnpm add @rbxts/react @rbxts/react-roblox # 🔴 See below ``` -------------------------------- ### Install React DevTools Dependencies Source: https://github.com/littensy/rbxts-react/blob/main/README.md Install @rbxts/react-globals and @rbxts/react-devtools-core for React DevTools integration. ```sh npm install @rbxts/react-globals @rbxts/react-devtools-core yarn add @rbxts/react-globals @rbxts/react-devtools-core pnpm add @rbxts/react-globals @rbxts/react-devtools-core # 🔴 See above ``` -------------------------------- ### Install @rbxts/react and @rbxts/react-roblox Source: https://context7.com/littensy/rbxts-react/llms.txt Install the core packages for React development in Roblox using npm. ```sh npm install @rbxts/react @rbxts/react-roblox ``` -------------------------------- ### useContext for Theme Management Source: https://context7.com/littensy/rbxts-react/llms.txt Use useContext to access context values provided by a nearest Provider. This example demonstrates managing a theme and toggling it via a button. ```tsx import React, { createContext, useContext, useState } from "@rbxts/react"; interface ThemeContext { theme: "light" | "dark"; toggleTheme: () => void; } const ThemeContext = createContext({ theme: "light", toggleTheme: () => {}, }); function ThemeProvider({ children }: { children: React.ReactNode }) { const [theme, setTheme] = useState<"light" | "dark">("light"); const toggleTheme = () => { setTheme((prev) => (prev === "light" ? "dark" : "light")); }; return ( {children} ); } function ThemedButton() { const { theme, toggleTheme } = useContext(ThemeContext); return ( ); } // Usage function App() { return ( ); } ``` -------------------------------- ### Function Component Example Source: https://github.com/littensy/rbxts-react/blob/main/README.md Example of a function component that uses useState to manage a counter. ```tsx import React, { useState } from "@rbxts/react"; interface CounterProps { initialCount: number; } export function Counter({ initialCount }: CounterProps) { const [count, setCount] = useState(initialCount); return ( setCount(count + 1), }} /> ); } ``` -------------------------------- ### Class Component Example Source: https://github.com/littensy/rbxts-react/blob/main/README.md Example of a class component that uses state to manage a counter, decorated with @ReactComponent. ```tsx import React, { Component, ReactComponent } from "@rbxts/react"; interface CounterProps { initialCount: number; } interface CounterState { count: number; } @ReactComponent export class Counter extends Component { state: CounterState = { count: this.props.initialCount, }; render() { return ( this.setState({ count: this.state.count + 1 }), }} /> ); } } ``` -------------------------------- ### Check for Conflicting React Installations Source: https://github.com/littensy/rbxts-react/blob/main/README.md Use `npm ls @rbxts/roact` to identify packages depending on an outdated version of `@rbxts/react-ts`. Update these packages or address conflicts to resolve rendering errors. ```sh npm ls @rbxts/roact ``` -------------------------------- ### Update roblox-ts CLI Source: https://github.com/littensy/rbxts-react/blob/main/README.md Ensure you are using the latest version of roblox-ts to resolve compilation errors related to jsxFactory. Uninstall global installations before installing the latest version. ```sh npm uninstall -g roblox-ts npm install -D roblox-ts@latest ``` -------------------------------- ### useRef for DOM Access and Mutable Values Source: https://context7.com/littensy/rbxts-react/llms.txt Use useRef to get a mutable reference to Roblox instances, like focusing a textbox on mount. It can also store mutable values that don't trigger re-renders, useful for interval counters. ```tsx import React, { useRef, useEffect } from "@rbxts/react"; function FocusableInput() { const textBoxRef = useRef(); useEffect(() => { // Focus the textbox on mount if (textBoxRef.current) { textBoxRef.current.CaptureFocus(); } }, []); return ( ); } // Using ref for mutable values that don't trigger re-renders function IntervalCounter() { const countRef = useRef(0); const [displayCount, setDisplayCount] = useState(0); useEffect(() => { const interval = task.spawn(() => { while (true) { task.wait(1); countRef.current += 1; } }); return () => task.cancel(interval); }, []); return ( setDisplayCount(countRef.current), }} /> ); } ``` -------------------------------- ### Initialize React DevTools Backend Source: https://github.com/littensy/rbxts-react/blob/main/README.md Initialize React DevTools before importing React. Set __DEV__ and __PROFILE__ flags as needed. ```ts import { backend } from "@rbxts/react-devtools-core"; import ReactGlobals from "@rbxts/react-globals"; // The DEV flag enables some DevTools features you otherwise wouldn't have ReactGlobals.__DEV__ = true; // The PROFILE flag allows you to run the DevTools profiler ReactGlobals.__PROFILE__ = true; backend.connectToDevtools(); ``` -------------------------------- ### Configure Rojo Project File Source: https://github.com/littensy/rbxts-react/blob/main/README.md Add the following to your Rojo project file under the node_modules folder to ensure correct module resolution. ```json "node_modules": { "$className": "Folder", "@rbxts": { "$path": "node_modules/@rbxts" }, "@rbxts-js": { "$path": "node_modules/@rbxts-js" } } ``` -------------------------------- ### Create Root for React Application Source: https://context7.com/littensy/rbxts-react/llms.txt Creates a root to display React components inside a Roblox instance. This is the entry point for rendering React applications in Roblox. Remember to unmount when done. ```tsx import React, { StrictMode } from "@rbxts/react"; import { createPortal, createRoot } from "@rbxts/react-roblox"; import { Players } from "@rbxts/services"; const playerGui = Players.LocalPlayer.WaitForChild("PlayerGui"); const root = createRoot(new Instance("Folder")); root.render( {createPortal(, playerGui)} ); // Unmount when done root.unmount(); ``` -------------------------------- ### Configure React Globals and DevTools Source: https://context7.com/littensy/rbxts-react/llms.txt Set React global flags like __DEV__, __PROFILE__, and __EXPERIMENTAL__ before importing React. Connect to React DevTools for debugging. Ensure React is imported after these configurations. ```tsx import ReactGlobals from "@rbxts/react-globals"; import { backend } from "@rbxts/react-devtools-core"; // Enable development mode (must be set BEFORE importing React) ReactGlobals.__DEV__ = true; // Enable profiling ReactGlobals.__PROFILE__ = true; // Enable experimental features ReactGlobals.__EXPERIMENTAL__ = true; // Connect to React DevTools backend.connectToDevtools({ host: "localhost", port: 8097, useHttps: false, isAppActive: () => true, profileOnStart: false, }); // Now import React import React from "@rbxts/react"; import { createRoot } from "@rbxts/react-roblox"; ``` -------------------------------- ### Configure Rojo Project for Node Modules Source: https://context7.com/littensy/rbxts-react/llms.txt Add the node_modules configuration to your Rojo project file to include the React packages. ```json { "node_modules": { "$className": "Folder", "@rbxts": { "$path": "node_modules/@rbxts" }, "@rbxts-js": { "$path": "node_modules/@rbxts-js" } } } ``` -------------------------------- ### PNPM Configuration for @rbxts Source: https://github.com/littensy/rbxts-react/blob/main/README.md If using PNPM, create a .npmrc file in your project root with this content to hoist @rbxts packages. ```ini public-hoist-pattern[]=*@rbxts* ``` -------------------------------- ### Use StrictMode and Suspense for Components Source: https://context7.com/littensy/rbxts-react/llms.txt Employ StrictMode for development checks and Suspense for handling asynchronous component loading. Lazy-load components to improve initial load times. ```tsx import React, { StrictMode, Suspense, lazy } from "@rbxts/react"; import { createRoot, createPortal } from "@rbxts/react-roblox"; // Lazy-loaded component const HeavyComponent = lazy(() => import("./HeavyComponent")); function App() { return ( } > ); } const root = createRoot(new Instance("Folder")); root.render(); ``` -------------------------------- ### Test Asynchronous Components with act() Source: https://context7.com/littensy/rbxts-react/llms.txt Wrap rendering and updates in act() to ensure effects are flushed synchronously during tests. Use synchronous act for immediate updates and await async act for updates after promises or delays. ```tsx import React, { useState, useEffect } from "@rbxts/react"; import { createRoot, act } from "@rbxts/react-roblox"; function AsyncComponent() { const [data, setData] = useState(); useEffect(() => { task.delay(0.1, () => setData("Loaded")); }, []); return ; } // In your test async function testAsyncComponent() { const container = new Instance("Folder"); const root = createRoot(container); // Synchronous act for immediate updates act(() => { root.render(); }); // Async act for updates that happen after promises/delays await act(async () => { await Promise.delay(0.2); }); // Assertions here root.unmount(); } ``` -------------------------------- ### useMemo for Expensive Calculations Source: https://context7.com/littensy/rbxts-react/llms.txt Use useMemo to memoize the result of an expensive calculation. The calculation only re-runs when its dependencies change. ```tsx import React, { useState, useMemo } from "@rbxts/react"; interface Item { id: number; name: string; category: string; } function FilteredList({ items }: { items: Item[] }) { const [filter, setFilter] = useState(""); const [category, setCategory] = useState("all"); // Only recompute when items, filter, or category changes const filteredItems = useMemo(() => { return items.filter((item) => { const matchesFilter = item.name.lower().find(filter.lower()) !== undefined; const matchesCategory = category === "all" || item.category === category; return matchesFilter && matchesCategory; }); }, [items, filter, category]); return ( setFilter(rbx.Text) }} /> {filteredItems.map((item) => ( ))} ); } ``` -------------------------------- ### Create Portal for UI Elements Source: https://context7.com/littensy/rbxts-react/llms.txt Creates a portal that renders children into a different part of the Roblox instance hierarchy. Useful for rendering UI elements to PlayerGui from anywhere in your component tree. ```tsx import React from "@rbxts/react"; import { createPortal } from "@rbxts/react-roblox"; import { Players } from "@rbxts/services"; interface ModalProps { children: React.ReactNode; } function Modal({ children }: ModalProps) { const playerGui = Players.LocalPlayer.WaitForChild("PlayerGui"); return createPortal( {children} , playerGui, "modal-portal" ); } ``` -------------------------------- ### Configure tsconfig.json for JSX Source: https://github.com/littensy/rbxts-react/blob/main/README.md Set up your tsconfig.json JSX options to use React's createElement and Fragment factories. ```json "compilerOptions": { "jsxFactory": "React.createElement", "jsxFragmentFactory": "React.Fragment" } ``` -------------------------------- ### Mount React App Source: https://github.com/littensy/rbxts-react/blob/main/README.md Render your React application into the Roblox environment using createRoot and createPortal. ```tsx import React, { StrictMode } from "@rbxts/react"; import { createPortal, createRoot } from "@rbxts/react-roblox"; const root = createRoot(new Instance("Folder")); root.render({createPortal(, playerGui)}); ``` -------------------------------- ### Correctly Render Function Components Source: https://github.com/littensy/rbxts-react/blob/main/README.md Always render function components using JSX tags (e.g., ``) instead of calling them directly (e.g., `App()`). Incorrect rendering can lead to hook-related errors. ```tsx ; // 🟢 Good App(); // 🔴 Bad ``` -------------------------------- ### Instance Props and Events Source: https://context7.com/littensy/rbxts-react/llms.txt Handle Roblox instance properties, events, and change handlers using special prop patterns within React components. Event handlers receive the instance as the first argument. ```tsx import React from "@rbxts/react"; function RobloxComponent() { return ( print(`Button ${rbx.Name} clicked`), MouseEnter: (rbx) => { rbx.BackgroundColor3 = new Color3(0.3, 0.5, 0.9); }, MouseLeave: (rbx) => { rbx.BackgroundColor3 = new Color3(0.2, 0.4, 0.8); }, }} // Property change handlers Change={{ Text: (rbx) => print(`Text changed to: ${rbx.Text}`), AbsoluteSize: (rbx) => print(`Size: ${rbx.AbsoluteSize}`), }} // CollectionService tag Tag="interactive-button" /> ); } ``` -------------------------------- ### Fragment Usage Source: https://context7.com/littensy/rbxts-react/llms.txt Use Fragments to group multiple elements without adding extra nodes to the component hierarchy. Supports both explicit import and shorthand syntax. ```tsx import React, { Fragment } from "@rbxts/react"; function ListWithLayout() { return ( ); } ``` ```tsx // Shorthand syntax function ShorthandFragment() { return ( <> ); } ``` -------------------------------- ### Configure tsconfig.json for React Source: https://github.com/littensy/rbxts-react/blob/main/README.md Set the correct jsxFactory and jsxFragmentFactory in your tsconfig.json to avoid 'nil cannot be used as a JSX component' errors. This ensures Roact is used correctly for JSX. ```json { "compilerOptions": { "jsxFactory": "React.createElement", "jsxFragmentFactory": "React.Fragment" } } ``` -------------------------------- ### useEffect for Timers and Data Fetching Source: https://context7.com/littensy/rbxts-react/llms.txt Use useEffect to handle side effects like timers or data fetching. The cleanup function ensures resources are released on unmount. The dependency array controls when the effect re-runs. ```tsx import React, { useState, useEffect } from "@rbxts/react"; import { RunService } from "@rbxts/services"; function Timer() { const [elapsed, setElapsed] = useState(0); useEffect(() => { const connection = RunService.Heartbeat.Connect((deltaTime) => { setElapsed((prev) => prev + deltaTime); }); // Cleanup function runs on unmount return () => { connection.Disconnect(); }; }, []); // Empty deps array means effect runs once on mount return ( ); } // Effect with dependencies function DataFetcher({ userId }: { userId: string }) { const [data, setData] = useState(); useEffect(() => { // Effect runs when userId changes print(`Fetching data for user: ${userId}`); setData(`Data for ${userId}`); }, [userId]); return ; } ``` -------------------------------- ### Forward Ref for Exposing Instance Source: https://context7.com/littensy/rbxts-react/llms.txt Use forwardRef to pass a ref down to a child component, allowing the parent to access the child's underlying instance or a custom imperative handle. ```tsx import React, { forwardRef, useRef, useImperativeHandle } from "@rbxts/react"; // Simple forward ref const FancyButton = forwardRef((props, ref) => ( )); // With useImperativeHandle for custom ref API interface InputHandle { focus: () => void; clear: () => void; getValue: () => string; } const CustomInput = forwardRef((props, ref) => { const textBoxRef = useRef(); useImperativeHandle(ref, () => ({ focus: () => textBoxRef.current?.CaptureFocus(), clear: () => { if (textBoxRef.current) { textBoxRef.current.Text = ""; } }, getValue: () => textBoxRef.current?.Text ?? "", })); return ( ); }); // Usage function Form() { const inputRef = useRef(); const handleSubmit = () => { const value = inputRef.current?.getValue(); print(`Submitted: ${value}`); inputRef.current?.clear(); }; return ( ); } ``` -------------------------------- ### Class Component Implementation Source: https://context7.com/littensy/rbxts-react/llms.txt Use class components for managing state and lifecycle methods in React for Roblox. Ensure all necessary lifecycle methods like componentDidMount and componentDidUpdate are implemented as needed. ```tsx import React, { Component, ReactComponent, ErrorInfo } from "@rbxts/react"; interface CounterProps { initialCount: number; } interface CounterState { count: number; } @ReactComponent export class Counter extends Component { state: CounterState = { count: this.props.initialCount, }; componentDidMount() { print("Counter mounted"); } componentDidUpdate(prevProps: CounterProps, prevState: CounterState) { if (prevState.count !== this.state.count) { print(`Count changed from ${prevState.count} to ${this.state.count}`); } } componentWillUnmount() { print("Counter will unmount"); } render() { return ( this.setState({ count: this.state.count + 1 }), }} /> ); } } ``` -------------------------------- ### useCallback for Memoizing Callbacks Source: https://context7.com/littensy/rbxts-react/llms.txt Use useCallback to memoize callback functions. This is particularly useful when passing callbacks to optimized child components (like those wrapped in React.memo) to prevent unnecessary re-renders. ```tsx import React, { useState, useCallback, memo } from "@rbxts/react"; interface ButtonProps { onClick: () => void; label: string; } const MemoizedButton = memo(function Button({ onClick, label }: ButtonProps) { print(`Rendering button: ${label}`); return ( ); }); function Parent() { const [count, setCount] = useState(0); const [otherState, setOtherState] = useState(0); // Without useCallback, this creates a new function on every render const handleClick = useCallback(() => { setCount((c) => c + 1); }, []); return ( {/* Button won't re-render when otherState changes */} setOtherState((s) => s + 1) }} /> ); } ``` -------------------------------- ### useReducer for Complex State Logic Source: https://context7.com/littensy/rbxts-react/llms.txt Use useReducer when state updates depend on previous state or involve multiple sub-values. It requires a reducer function and an initial state. ```tsx import React, { useReducer } from "@rbxts/react"; interface State { count: number; step: number; } type Action = | { type: "increment" } | { type: "decrement" } | { type: "setStep"; payload: number } | { type: "reset" }; function reducer(state: State, action: Action): State { switch (action.type) { case "increment": return { ...state, count: state.count + state.step }; case "decrement": return { ...state, count: state.count - state.step }; case "setStep": return { ...state, step: action.payload }; case "reset": return { count: 0, step: 1 }; default: return state; } } function StepCounter() { const [state, dispatch] = useReducer(reducer, { count: 0, step: 1 }); return ( dispatch({ type: "increment" }) }} /> dispatch({ type: "decrement" }) }} /> dispatch({ type: "setStep", payload: state.step + 1 }) }} /> dispatch({ type: "reset" }) }} /> ); } ``` -------------------------------- ### Implement an Error Boundary in React Source: https://github.com/littensy/rbxts-react/blob/main/README.md Use this component to catch JavaScript errors anywhere in your child component tree, log those errors, and display a fallback UI. ```tsx import React, { Component, ErrorInfo, ReactComponent } from "@rbxts/react"; interface ErrorBoundaryProps { fallback: (error: unknown) => React.Element; } interface ErrorBoundaryState { hasError: boolean; message?: unknown; } @ReactComponent export class ErrorBoundary extends Component { state: ErrorBoundaryState = { hasError: false, }; componentDidCatch(message: unknown, info: ErrorInfo) { warn(message, info.componentStack); this.setState({ hasError: true, message: `${message} ${info.componentStack}`, }); } render() { if (this.state.hasError) { return this.props.fallback(this.state.message); } else { return this.props.children; } } } ``` -------------------------------- ### Use Binding for Animations Source: https://context7.com/littensy/rbxts-react/llms.txt Use useBinding to create mutable values for animations or frequently changing properties. Updates to these bindings do not trigger component re-renders. ```tsx import React, { useBinding, useEffect } from "@rbxts/react"; import { TweenService, RunService } from "@rbxts/services"; function AnimatedFrame() { const [transparency, setTransparency] = useBinding(0); const [position, setPosition] = useBinding(new UDim2(0, 0, 0, 0)); useEffect(() => { // Animate transparency let direction = 1; const connection = RunService.Heartbeat.Connect((dt) => { const current = transparency.getValue(); let newValue = current + dt * direction; if (newValue >= 1) { newValue = 1; direction = -1; } else if (newValue <= 0) { newValue = 0; direction = 1; } setTransparency(newValue); }); return () => connection.Disconnect(); }, []); return ( ); } // Using binding.map() for derived values function MappedBinding() { const [progress, setProgress] = useBinding(0); return ( new UDim2(p, 0, 0, 50))} BackgroundColor3={progress.map((p) => new Color3(p, 1 - p, 0) )} /> ); } ``` -------------------------------- ### Error Boundary Implementation Source: https://context7.com/littensy/rbxts-react/llms.txt Implement error boundaries using class components to catch JavaScript errors in the child component tree. Use getDerivedStateFromError to update state and componentDidCatch to log errors. ```tsx import React, { Component, ErrorInfo, ReactComponent } from "@rbxts/react"; interface ErrorBoundaryProps { fallback: (error: unknown) => React.Element; children?: React.ReactNode; } interface ErrorBoundaryState { hasError: boolean; message?: unknown; } @ReactComponent export class ErrorBoundary extends Component { state: ErrorBoundaryState = { hasError: false, }; static getDerivedStateFromError(error: Error): Partial { return { hasError: true, message: error.message }; } componentDidCatch(message: unknown, info: ErrorInfo) { warn(message, info.componentStack); this.setState({ hasError: true, message: `${message} ${info.componentStack}`, }); } render() { if (this.state.hasError) { return this.props.fallback(this.state.message); } return this.props.children; } } ``` ```tsx // Usage function App() { return ( ( )}> ); } ``` -------------------------------- ### Create Binding Outside Components Source: https://context7.com/littensy/rbxts-react/llms.txt Use createBinding to define mutable values at the module scope. These bindings can be joined and mapped within components. ```tsx import React, { createBinding, joinBindings } from "@rbxts/react"; // Create bindings at module scope const [mouseX, setMouseX] = createBinding(0); const [mouseY, setMouseY] = createBinding(0); // Join multiple bindings into one const mousePosition = joinBindings({ x: mouseX, y: mouseY }); function MouseFollower() { return ( new UDim2(0, x, 0, y) )} Size={new UDim2(0, 20, 0, 20)} AnchorPoint={new Vector2(0.5, 0.5)} BackgroundColor3={new Color3(1, 1, 0)} /> ); } ``` -------------------------------- ### Memoize Component for Performance Source: https://context7.com/littensy/rbxts-react/llms.txt Use memo to prevent unnecessary re-renders of a component when its props have not changed. A custom comparison function can be provided for deep comparisons. ```tsx import React, { memo, useState } from "@rbxts/react"; interface ItemProps { id: number; name: string; onSelect: (id: number) => void; } // Component only re-renders when props change const ListItem = memo(function ListItem({ id, name, onSelect }: ItemProps) { print(`Rendering item: ${name}`); return ( onSelect(id) }} /> ); }); // With custom comparison function const DeepCompareItem = memo( function DeepCompareItem({ data }: { data: { nested: { value: number } } }) { return ; }, (prevProps, nextProps) => { // Only re-render if nested value actually changed return prevProps.data.nested.value === nextProps.data.nested.value; } ); ``` -------------------------------- ### useState Hook for State Management Source: https://context7.com/littensy/rbxts-react/llms.txt Returns a stateful value and a function to update it. The state setter triggers re-renders when called. Supports functional updates for previous state. ```tsx import React, { useState } from "@rbxts/react"; interface CounterProps { initialCount: number; } export function Counter({ initialCount }: CounterProps) { const [count, setCount] = useState(initialCount); return ( setCount(count + 1), }} /> ); } // With functional updates function AdvancedCounter() { const [count, setCount] = useState(0); const increment = () => setCount((prev) => prev + 1); const decrement = () => setCount((prev) => prev - 1); return ( ); } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.