Logo
KNEXT.JS
  • Blog
  • Docs
KNEXT.JS
  • Home
  • Docs
    • Components
    • Getting Started
    • Guides
    • Patterns
  • Blog
    • Patterns
    • Test
  1. Home
  2. blog
  3. patterns
  4. useful react patterns

KNEXT.js

Your next project, supercharged with modern web development tools and best practices.

Resources

  • Documentation
  • Components
  • Templates

Company

  • About
  • Blog
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2025 KNEXT.js. All rights reserved.

GitHubBluesky
4/27/2024•6 min read

Useful React 19 Development Patterns

React continues to evolve, introducing new patterns and best practices that enhance the way developers build scalable and maintainable applications. With React 19, several advanced development patterns emerge, providing more flexibility and efficiency. In this article, we'll explore some of the most useful React 19 development patterns that can elevate your React projects.

1. Custom Hooks for State Management

Custom Hooks allow you to extract and reuse stateful logic across multiple components without changing the component hierarchy. They promote cleaner code and better separation of concerns.

2. Compound Components

Compound Components provide a way to create flexible and reusable components by leveraging React's context API. They allow parent and child components to communicate seamlessly.

3. Render Props

Render Props is a pattern where a component's prop is a function that returns a React element. It offers a way to share code between components using a prop whose value is a function.

4. Higher-Order Components (HOC)

Higher-Order Components are functions that take a component and return a new component, enhancing the original component with additional props or functionalities.

5. Context for Global State

The Context API provides a way to pass data through the component tree without having to pass props down manually at every level, making it ideal for global state management.

6. Portals for Modals and Tooltips

Portals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component, which is particularly useful for modals and tooltips.

7. Error Boundaries

Error Boundaries catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the component tree that crashed.

8. Suspense and Lazy Loading

React's Suspense and lazy loading features allow for code-splitting and asynchronous loading of components, improving performance by reducing the initial load time.

9. State Reducers with useReducer

The useReducer hook provides a way to manage complex state logic in React components, especially when dealing with multiple related state variables.

10. Forwarding Refs

Forwarding refs allow components to pass refs down to their children, enabling parent components to directly interact with DOM elements or child component instances.

Conclusion

Embracing these React 19 development patterns can significantly enhance your application's scalability, maintainability, and performance. By leveraging custom hooks, compound components, context API, and other advanced patterns, you can build more robust and efficient React applications. Stay updated with the latest React features and best practices to continue evolving your development skills.

// Tabs.js
import React, { createContext, useContext, useState } from 'react';

const TabsContext = createContext();

export function Tabs({ children }) {
const [activeIndex, setActiveIndex] = useState(0);
return (
<TabsContext.Provider value={{ activeIndex, setActiveIndex }}>
<div className="tabs">{children}</div>
</TabsContext.Provider>
);
}

export function TabList({ children }) {
return <div className="tab-list">{children}</div>;
}

export function Tab({ index, children }) {
const { activeIndex, setActiveIndex } = useContext(TabsContext);
return (
<button
className={`tab ${activeIndex === index ? 'active' : ''}`}
onClick={() => setActiveIndex(index)}
>
{children}
</button>
);
}

export function TabPanel({ index, children }) {
const { activeIndex } = useContext(TabsContext);
return activeIndex === index ? <div className="tab-panel">{children}</div> : null;
}
// MouseTracker.js
import React, { Component } from 'react';

class MouseTracker extends Component {
state = { x: 0, y: 0 };

handleMouseMove = event => {
this.setState({
x: event.clientX,
y: event.clientY,
});
};

render() {
return (
<div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}>
{this.props.render(this.state)}
</div>
);
}
}

export default MouseTracker;

// Usage
// <MouseTracker render={({ x, y }) => (
// <h1>The mouse position is ({x}, {y})</h1>
// )} />
// withLoading.js
import React from 'react';

const withLoading = WrappedComponent => {
return function WithLoadingComponent({ isLoading, ...props }) {
if (isLoading) {
return <div>Loading...</div>;
}
return <WrappedComponent {...props} />;
};
};

export default withLoading;

// Usage
// const UserListWithLoading = withLoading(UserList);
// <UserListWithLoading isLoading={true} users={[]} />
// ThemeContext.js
import React, { createContext, useState } from 'react';

export const ThemeContext = createContext();

export function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () =>
setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light'));

return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}

// Usage
// import { ThemeContext } from './ThemeContext';
// const { theme, toggleTheme } = useContext(ThemeContext);
// Modal.js
import React from 'react';
import ReactDOM from 'react-dom';

function Modal({ isOpen, onClose, children }) {
if (!isOpen) return null;

return ReactDOM.createPortal(
<div className="modal-overlay">
<div className="modal-content">
<button onClick={onClose}>Close</button>
{children}
</div>
</div>,
document.getElementById('modal-root')
);
}

export default Modal;

// Usage
// <Modal isOpen={isModalOpen} onClose={() => setModalOpen(false)}>
// <p>Modal Content</p>
// </Modal>
// ErrorBoundary.js
import React, { Component } from 'react';

class ErrorBoundary extends Component {
state = { hasError: false };

static getDerivedStateFromError(error) {
return { hasError: true };
}

componentDidCatch(error, info) {
// Log error to an error reporting service
console.error("ErrorBoundary caught an error", error, info);
}

render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}

export default ErrorBoundary;

// Usage
// <ErrorBoundary>
// <MyComponent />
// </ErrorBoundary>
// LazyComponent.js
import React, { Suspense, lazy } from 'react';

const LazyLoadedComponent = lazy(() => import('./HeavyComponent'));

function MyComponent() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyLoadedComponent />
</Suspense>
);
}

export default MyComponent;
// FancyButton.js
import React from 'react';

const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="fancy-button">
{props.children}
</button>
));

export default FancyButton;

// Usage
// import React, { useRef } from 'react';
// const ref = useRef();
// <FancyButton ref={ref}>Click Me!</FancyButton>
// useLocalStorage.js
import { useState, useEffect } from 'react';

function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.error(error);
return initialValue;
}
});

const setValue = value => {
try {
const valueToStore =
value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
console.error(error);
}
};

return [storedValue, setValue];
}

export default useLocalStorage;
// reducer.js
export const initialState = { count: 0 };

export function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error();
}
}

// Counter.js
import React, { useReducer } from 'react';
import { reducer, initialState } from './reducer';

function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);

return (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: 'increment' })}>
+
</button>
<button onClick={() => dispatch({ type: 'decrement' })}>
-
</button>
</>
);
}

export default Counter;