2026-01-20 00:46:06
React Offcanvas is a simple library for creating offcanvas (side panel) components in React applications. It provides an easy way to display content in a slide-out panel that overlays or pushes the main content, perfect for navigation menus, filters, and additional information panels. This guide walks through setting up and creating offcanvas panels using React Offcanvas with React, from installation to a working implementation. This is part 43 of a series on using React Offcanvas with React.
Before you begin, make sure you have:
Install React Offcanvas using your preferred package manager:
npm install react-offcanvas
Or with yarn:
yarn add react-offcanvas
Or with pnpm:
pnpm add react-offcanvas
After installation, your package.json should include:
{
"dependencies": {
"react-offcanvas": "^0.4.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
}
React Offcanvas requires minimal setup. Import the component and styles:
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
Let's create a simple offcanvas panel. Create a new file src/OffcanvasExample.jsx:
// src/OffcanvasExample.jsx
import React, { useState } from 'react';
import Offcanvas from 'react-offcanvas';
function OffcanvasExample() {
const [isOpen, setIsOpen] = useState(false);
const toggleOffcanvas = () => {
setIsOpen(!isOpen);
};
return (
<div style={{ padding: '20px' }}>
<h2>Offcanvas Example</h2>
<button
onClick={toggleOffcanvas}
style={{
padding: '10px 20px',
backgroundColor: '#007bff',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
}}
>
Open Offcanvas
</button>
<Offcanvas
width={300}
transitionDuration={300}
isMenuOpen={isOpen}
effect="overlay"
position="right"
>
<div style={{ padding: '20px' }}>
<h3>Offcanvas Panel</h3>
<p>This is the offcanvas content.</p>
<button
onClick={toggleOffcanvas}
style={{
padding: '8px 16px',
backgroundColor: '#dc3545',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
marginTop: '20px'
}}
>
Close
</button>
</div>
</Offcanvas>
</div>
);
}
export default OffcanvasExample;
Update your App.jsx:
// src/App.jsx
import React from 'react';
import OffcanvasExample from './OffcanvasExample';
import './App.css';
function App() {
return (
<div className="App">
<OffcanvasExample />
</div>
);
}
export default App;
This creates a basic offcanvas panel that slides in from the right when the button is clicked.
React Offcanvas provides several key features:
Key concepts:
useState to track whether the offcanvas is open or closedHere's an example with different positions and effects:
// src/MultipleOffcanvasExample.jsx
import React, { useState } from 'react';
import Offcanvas from 'react-offcanvas';
function MultipleOffcanvasExample() {
const [leftOpen, setLeftOpen] = useState(false);
const [rightOpen, setRightOpen] = useState(false);
const [topOpen, setTopOpen] = useState(false);
return (
<div style={{ padding: '20px' }}>
<h2>Multiple Offcanvas Examples</h2>
<div style={{ display: 'flex', gap: '10px', flexWrap: 'wrap', marginTop: '20px' }}>
<button
onClick={() => setLeftOpen(!leftOpen)}
style={{
padding: '10px 20px',
backgroundColor: '#28a745',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
}}
>
Open Left
</button>
<button
onClick={() => setRightOpen(!rightOpen)}
style={{
padding: '10px 20px',
backgroundColor: '#007bff',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
}}
>
Open Right
</button>
<button
onClick={() => setTopOpen(!topOpen)}
style={{
padding: '10px 20px',
backgroundColor: '#ffc107',
color: 'black',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
}}
>
Open Top
</button>
</div>
<Offcanvas
width={250}
isMenuOpen={leftOpen}
effect="overlay"
position="left"
>
<div style={{ padding: '20px' }}>
<h3>Left Panel</h3>
<p>This panel slides in from the left.</p>
<button onClick={() => setLeftOpen(false)}>Close</button>
</div>
</Offcanvas>
<Offcanvas
width={300}
isMenuOpen={rightOpen}
effect="overlay"
position="right"
>
<div style={{ padding: '20px' }}>
<h3>Right Panel</h3>
<p>This panel slides in from the right.</p>
<button onClick={() => setRightOpen(false)}>Close</button>
</div>
</Offcanvas>
<Offcanvas
width="100%"
isMenuOpen={topOpen}
effect="overlay"
position="top"
>
<div style={{ padding: '20px' }}>
<h3>Top Panel</h3>
<p>This panel slides in from the top.</p>
<button onClick={() => setTopOpen(false)}>Close</button>
</div>
</Offcanvas>
</div>
);
}
export default MultipleOffcanvasExample;
Let's build a navigation menu with an offcanvas panel:
// src/NavigationWithOffcanvas.jsx
import React, { useState } from 'react';
import Offcanvas from 'react-offcanvas';
function NavigationWithOffcanvas() {
const [isOpen, setIsOpen] = useState(false);
const menuItems = [
{ id: 1, label: 'Home', href: '#home' },
{ id: 2, label: 'About', href: '#about' },
{ id: 3, label: 'Services', href: '#services' },
{ id: 4, label: 'Portfolio', href: '#portfolio' },
{ id: 5, label: 'Contact', href: '#contact' }
];
const toggleMenu = () => {
setIsOpen(!isOpen);
};
return (
<div>
<nav style={{
backgroundColor: '#2c3e50',
padding: '15px 30px',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
}}>
<div style={{ color: 'white', fontSize: '24px', fontWeight: 'bold' }}>
MyApp
</div>
<button
onClick={toggleMenu}
style={{
padding: '8px 16px',
backgroundColor: 'transparent',
border: '2px solid white',
color: 'white',
borderRadius: '4px',
cursor: 'pointer',
fontSize: '16px'
}}
>
☰ Menu
</button>
</nav>
<Offcanvas
width={280}
isMenuOpen={isOpen}
effect="overlay"
position="right"
transitionDuration={300}
>
<div style={{
padding: '30px 20px',
height: '100%',
backgroundColor: '#34495e',
color: 'white'
}}>
<div style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: '30px',
paddingBottom: '20px',
borderBottom: '2px solid rgba(255, 255, 255, 0.3)'
}}>
<h2 style={{ margin: 0 }}>Navigation</h2>
<button
onClick={toggleMenu}
style={{
background: 'none',
border: 'none',
color: 'white',
fontSize: '24px',
cursor: 'pointer',
padding: '5px 10px'
}}
>
×
</button>
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: '10px' }}>
{menuItems.map(item => (
<a
key={item.id}
href={item.href}
onClick={toggleMenu}
style={{
color: 'white',
textDecoration: 'none',
padding: '15px',
borderRadius: '8px',
transition: 'background-color 0.3s',
fontSize: '18px'
}}
onMouseEnter={(e) => e.target.style.backgroundColor = 'rgba(255, 255, 255, 0.1)'}
onMouseLeave={(e) => e.target.style.backgroundColor = 'transparent'}
>
{item.label}
</a>
))}
</div>
</div>
</Offcanvas>
<div style={{ padding: '40px' }}>
<h1>Welcome to My App</h1>
<p>Click the menu button to open the offcanvas navigation panel.</p>
</div>
</div>
);
}
export default NavigationWithOffcanvas;
Now create a filter panel component:
// src/FilterPanel.jsx
import React, { useState } from 'react';
import Offcanvas from 'react-offcanvas';
function FilterPanel() {
const [isOpen, setIsOpen] = useState(false);
const [filters, setFilters] = useState({
category: '',
priceRange: '',
sortBy: ''
});
const handleFilterChange = (name, value) => {
setFilters(prev => ({ ...prev, [name]: value }));
};
const applyFilters = () => {
console.log('Applied filters:', filters);
setIsOpen(false);
};
const clearFilters = () => {
setFilters({ category: '', priceRange: '', sortBy: '' });
};
return (
<div style={{ padding: '20px' }}>
<button
onClick={() => setIsOpen(true)}
style={{
padding: '10px 20px',
backgroundColor: '#007bff',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
}}
>
Open Filters
</button>
<Offcanvas
width={320}
isMenuOpen={isOpen}
effect="overlay"
position="right"
>
<div style={{ padding: '30px 20px', height: '100%' }}>
<div style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: '30px',
paddingBottom: '20px',
borderBottom: '2px solid #ddd'
}}>
<h2 style={{ margin: 0 }}>Filters</h2>
<button
onClick={() => setIsOpen(false)}
style={{
background: 'none',
border: 'none',
fontSize: '24px',
cursor: 'pointer',
padding: '5px 10px'
}}
>
×
</button>
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: '20px' }}>
<div>
<label style={{ display: 'block', marginBottom: '8px', fontWeight: '500' }}>
Category
</label>
<select
value={filters.category}
onChange={(e) => handleFilterChange('category', e.target.value)}
style={{
width: '100%',
padding: '8px',
border: '1px solid #ddd',
borderRadius: '4px'
}}
>
<option value="">All Categories</option>
<option value="electronics">Electronics</option>
<option value="clothing">Clothing</option>
<option value="books">Books</option>
<option value="home">Home & Garden</option>
</select>
</div>
<div>
<label style={{ display: 'block', marginBottom: '8px', fontWeight: '500' }}>
Price Range
</label>
<select
value={filters.priceRange}
onChange={(e) => handleFilterChange('priceRange', e.target.value)}
style={{
width: '100%',
padding: '8px',
border: '1px solid #ddd',
borderRadius: '4px'
}}
>
<option value="">All Prices</option>
<option value="0-50">$0 - $50</option>
<option value="50-100">$50 - $100</option>
<option value="100-200">$100 - $200</option>
<option value="200+">$200+</option>
</select>
</div>
<div>
<label style={{ display: 'block', marginBottom: '8px', fontWeight: '500' }}>
Sort By
</label>
<select
value={filters.sortBy}
onChange={(e) => handleFilterChange('sortBy', e.target.value)}
style={{
width: '100%',
padding: '8px',
border: '1px solid #ddd',
borderRadius: '4px'
}}
>
<option value="">Default</option>
<option value="price-asc">Price: Low to High</option>
<option value="price-desc">Price: High to Low</option>
<option value="name-asc">Name: A to Z</option>
<option value="name-desc">Name: Z to A</option>
</select>
</div>
</div>
<div style={{
display: 'flex',
gap: '10px',
marginTop: '30px',
paddingTop: '20px',
borderTop: '2px solid #ddd'
}}>
<button
onClick={applyFilters}
style={{
flex: 1,
padding: '12px',
backgroundColor: '#007bff',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
fontSize: '16px'
}}
>
Apply Filters
</button>
<button
onClick={clearFilters}
style={{
flex: 1,
padding: '12px',
backgroundColor: '#6c757d',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
fontSize: '16px'
}}
>
Clear
</button>
</div>
</div>
</Offcanvas>
</div>
);
}
export default FilterPanel;
Update your App.jsx:
// src/App.jsx
import React from 'react';
import NavigationWithOffcanvas from './NavigationWithOffcanvas';
import FilterPanel from './FilterPanel';
import './App.css';
function App() {
return (
<div className="App">
<NavigationWithOffcanvas />
<div style={{ padding: '40px' }}>
<FilterPanel />
</div>
</div>
);
}
export default App;
This example demonstrates:
Offcanvas not appearing: Make sure the isMenuOpen prop is set to true and the component is properly rendered. Check that you're managing the state correctly with useState.
Panel not closing: Ensure you have a close button or function that sets isMenuOpen to false. The offcanvas won't close automatically unless you handle the state.
Styling issues: If the offcanvas doesn't look right, check for CSS conflicts. You can customize the appearance using inline styles on the content div inside the Offcanvas component.
Position not working: Make sure you're using a valid position value: 'left', 'right', 'top', or 'bottom'. The default is usually 'left'.
Animation not smooth: Adjust the transitionDuration prop to control animation speed. Higher values (in milliseconds) create slower animations.
Content overflow: If content is too long, add scrolling to the offcanvas content div using overflow-y: auto in the style.
Now that you have a basic understanding of React Offcanvas:
You've successfully set up React Offcanvas in your React application and created side panels for navigation and filters. React Offcanvas provides a simple solution for displaying content in slide-out panels with smooth animations.
react-offcanvas
React side panel
react-offcanvas tutorial
React slide-out menu
react-offcanvas installation
React offcanvas component
react-offcanvas example
React side navigation
react-offcanvas setup
React panel component
react-offcanvas customization
React overlay panel
react-offcanvas positioning
React side menu
react-offcanvas getting started
2026-01-20 00:45:07
You love NestJS. The decorators feel elegant. The structure keeps your codebase clean. TypeScript integration works well.
Then you add a new service.
You import it in one module. Export it in another. Inject it somewhere else. Suddenly, you get this error:
Nest can't resolve dependencies of the UserService (?).
Please make sure that the argument at index [0]
is available in the current context.
Sound familiar?
NestJS modules solve a real problem: dependency boundaries. They prevent chaos in large codebases.
But they come at a cost.
Every new service requires you to:
@Injectable()
providers arrayexports array if other modules need itHere's what a typical NestJS module looks like:
// user.module.ts
@Module({
imports: [
DatabaseModule,
ConfigModule,
AuthModule,
LoggingModule,
],
controllers: [UserController],
providers: [
UserService,
UserRepository,
UserValidator,
UserMapper,
],
exports: [UserService, UserRepository],
})
export class UserModule {}
This is boilerplate. Pure configuration overhead.
And it grows. Fast.
A medium-sized app has 20+ modules. Each module has 5-10 providers. You spend more time managing arrays than writing business logic.
The worst part? A typo in any array breaks your entire dependency graph. Debugging takes hours.
Rikta is a new TypeScript framework built on Fastify. It keeps the parts developers love about NestJS (decorators, DI, structure) and removes the module configuration entirely.
No imports arrays.
No exports arrays.
No providers arrays.
Decorate your class. Everything works.
// user.service.ts
import { Injectable } from '@riktajs/core';
@Injectable()
export class UserService {
getUsers() {
return ['Alice', 'Bob'];
}
}
// user.controller.ts
import { Controller, Get, Autowired } from '@riktajs/core';
import { UserService } from './user.service';
@Controller('/users')
export class UserController {
@Autowired()
private userService!: UserService;
@Get()
getUsers() {
return this.userService.getUsers();
}
}
That's it. No module file. No registration. Rikta scans your code at startup and resolves dependencies automatically.
Rikta uses three mechanisms:
1. Automatic Discovery
At startup, Rikta scans your project for classes decorated with @Controller() or @Injectable(). It builds a dependency graph from constructor parameters and @Autowired() decorators.
2. Global Provider Registry
All providers live in a single registry. Any injectable class is available anywhere in your app. No need to export or import.
3. Dependency Resolution
Rikta reads TypeScript metadata (via reflect-metadata) to understand what each class needs. It creates instances in the correct order and injects them automatically.
The framework detects circular dependencies during initialization and throws a clear error:
Error: Circular dependency detected:
UserService -> AuthService -> UserService
No cryptic stack traces. No runtime surprises.
Creating a new feature in NestJS:
// 1. Create the service
@Injectable()
export class PaymentService {
constructor(private configService: ConfigService) {}
}
// 2. Create the module
@Module({
imports: [ConfigModule],
providers: [PaymentService],
exports: [PaymentService],
})
export class PaymentModule {}
// 3. Import in app.module.ts
@Module({
imports: [PaymentModule, /* ... */],
})
export class AppModule {}
// 4. Import in any module that needs it
@Module({
imports: [PaymentModule],
providers: [OrderService],
})
export class OrderModule {}
Creating the same feature in Rikta:
@Injectable()
export class PaymentService {
@Autowired()
private configService!: ConfigService;
}
Done.
Rikta uses Fastify as its HTTP layer. Fastify handles up to 30,000 requests per second in benchmarks.
Benchmark results from the official repository:
| Metric | Rikta vs NestJS |
|---|---|
| Startup time | 43% faster |
| GET requests | 41% faster |
| POST requests | 25% faster |
| Route parameters | 46% faster |
Rikta adds minimal overhead (2-5%) over vanilla Fastify. You get dependency injection and decorators without sacrificing speed.
NestJS uses class-validator decorators for validation. This works, but you define types twice: once for TypeScript, once for validation.
Rikta integrates Zod natively. Define a schema once. Get validation and TypeScript types automatically.
import { Controller, Post, Body, z } from '@riktajs/core';
const CreateUserSchema = z.object({
email: z.string().email(),
name: z.string().min(2),
age: z.number().optional(),
});
@Controller('/users')
export class UserController {
@Post()
create(@Body(CreateUserSchema) user: z.infer<typeof CreateUserSchema>) {
// 'user' is validated AND typed
// Invalid requests return 400 automatically
return { created: user };
}
}
No duplicate type definitions. No manual error handling for validation failures.
Rikta works best for:
Consider NestJS if:
Create a new project in seconds:
npx @riktajs/cli new my-app
cd my-app
npm run dev
Your API runs at http://localhost:3000.
The CLI generates a complete project with:
Rikta is MIT licensed and open source.
Have you tried zero-config frameworks? What do you think about the module vs. autowiring tradeoff? Share your experience in the comments.
2026-01-20 00:40:29
Liquid syntax error: Unknown tag 'endraw'
2026-01-20 00:35:29
Reapop is a powerful, Redux-based notification system for React applications. It provides a flexible and scalable approach to managing notifications using Redux for state management, making it ideal for complex applications that need centralized notification handling. This guide walks through advanced usage of Reapop with React and Redux, including custom configurations, middleware integration, and complex notification patterns. This is part 36 of a series on using Reapop with React.
Before you begin, make sure you have:
Install Reapop and Redux dependencies:
npm install reapop react-redux redux
Or with yarn:
yarn add reapop react-redux redux
Or with pnpm:
pnpm add reapop react-redux redux
After installation, your package.json should include:
{
"dependencies": {
"reapop": "^4.0.0",
"react-redux": "^8.0.0",
"redux": "^4.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
}
Set up Redux store with Reapop reducer. First, create the Redux store:
// src/store/index.js
import { createStore, combineReducers } from 'redux';
import { reducer as notificationsReducer } from 'reapop';
const rootReducer = combineReducers({
notifications: notificationsReducer
});
export const store = createStore(rootReducer);
Now set up the provider and notification system in your main entry file:
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import { store } from './store';
import { NotificationsSystem } from 'reapop';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
<NotificationsSystem />
</Provider>
</React.StrictMode>
);
Let's create a simple notification component. Create a new file src/NotificationExample.jsx:
// src/NotificationExample.jsx
import React from 'react';
import { useDispatch } from 'react-redux';
import { notify } from 'reapop';
function NotificationExample() {
const dispatch = useDispatch();
const showSuccess = () => {
dispatch(notify({
title: 'Success!',
message: 'Operation completed successfully.',
status: 'success',
dismissible: true,
dismissAfter: 3000
}));
};
const showError = () => {
dispatch(notify({
title: 'Error!',
message: 'Something went wrong.',
status: 'error',
dismissible: true,
dismissAfter: 5000
}));
};
const showWarning = () => {
dispatch(notify({
title: 'Warning!',
message: 'Please review your input.',
status: 'warning',
dismissible: true,
dismissAfter: 4000
}));
};
const showInfo = () => {
dispatch(notify({
title: 'Info',
message: 'Here is some information.',
status: 'info',
dismissible: true,
dismissAfter: 3000
}));
};
return (
<div style={{ padding: '20px' }}>
<h2>Notification Examples</h2>
<div style={{ display: 'flex', gap: '10px', flexWrap: 'wrap' }}>
<button onClick={showSuccess}>Success</button>
<button onClick={showError}>Error</button>
<button onClick={showWarning}>Warning</button>
<button onClick={showInfo}>Info</button>
</div>
</div>
);
}
export default NotificationExample;
Update your App.jsx:
// src/App.jsx
import React from 'react';
import NotificationExample from './NotificationExample';
import './App.css';
function App() {
return (
<div className="App">
<NotificationExample />
</div>
);
}
export default App;
Reapop uses Redux for state management where:
Key concepts for advanced usage:
notify action creator to create notificationsHere's an example with custom configuration:
// src/store/index.js
import { createStore, combineReducers, applyMiddleware } from 'redux';
import { reducer as notificationsReducer, setUpNotifications } from 'reapop';
import thunk from 'redux-thunk';
// Configure notifications
setUpNotifications({
defaultProps: {
position: 'top-right',
dismissible: true,
dismissAfter: 5000
}
});
const rootReducer = combineReducers({
notifications: notificationsReducer
});
export const store = createStore(rootReducer, applyMiddleware(thunk));
Let's build a comprehensive notification system with custom hooks, middleware integration, and advanced features:
// src/hooks/useNotifications.js
import { useCallback } from 'react';
import { useDispatch } from 'react-redux';
import { notify, dismissNotification } from 'reapop';
export const useNotifications = () => {
const dispatch = useDispatch();
const showSuccess = useCallback((title, message, options = {}) => {
return dispatch(notify({
title,
message,
status: 'success',
dismissible: true,
dismissAfter: 3000,
...options
}));
}, [dispatch]);
const showError = useCallback((title, message, options = {}) => {
return dispatch(notify({
title,
message,
status: 'error',
dismissible: true,
dismissAfter: 5000,
...options
}));
}, [dispatch]);
const showWarning = useCallback((title, message, options = {}) => {
return dispatch(notify({
title,
message,
status: 'warning',
dismissible: true,
dismissAfter: 4000,
...options
}));
}, [dispatch]);
const showInfo = useCallback((title, message, options = {}) => {
return dispatch(notify({
title,
message,
status: 'info',
dismissible: true,
dismissAfter: 3000,
...options
}));
}, [dispatch]);
const showLoading = useCallback((title, message) => {
return dispatch(notify({
title,
message,
status: 'loading',
dismissible: false,
dismissAfter: 0
}));
}, [dispatch]);
const dismiss = useCallback((notificationId) => {
dispatch(dismissNotification(notificationId));
}, [dispatch]);
return {
showSuccess,
showError,
showWarning,
showInfo,
showLoading,
dismiss
};
};
Now create an advanced notification system component:
// src/AdvancedNotificationSystem.jsx
import React, { useState } from 'react';
import { useNotifications } from './hooks/useNotifications';
import { useDispatch } from 'react-redux';
import { dismissNotifications } from 'reapop';
function AdvancedNotificationSystem() {
const { showSuccess, showError, showWarning, showInfo, showLoading, dismiss } = useNotifications();
const dispatch = useDispatch();
const [formData, setFormData] = useState({
title: '',
message: '',
status: 'success'
});
const handleInputChange = (e) => {
const { name, value } = e.target;
setFormData(prev => ({ ...prev, [name]: value }));
};
const handleSubmit = (e) => {
e.preventDefault();
if (!formData.title || !formData.message) {
showError('Validation Error', 'Please fill in all fields.');
return;
}
const options = {
position: 'top-right',
dismissible: true
};
switch (formData.status) {
case 'success':
showSuccess(formData.title, formData.message, options);
break;
case 'error':
showError(formData.title, formData.message, options);
break;
case 'warning':
showWarning(formData.title, formData.message, options);
break;
case 'info':
showInfo(formData.title, formData.message, options);
break;
default:
showInfo(formData.title, formData.message, options);
}
setFormData({ title: '', message: '', status: 'success' });
};
const simulateApiCall = async () => {
const loadingId = showLoading('Processing', 'Processing your request...');
try {
// Simulate API call
await new Promise(resolve => setTimeout(resolve, 2000));
dismiss(loadingId);
showSuccess('Success', 'Operation completed successfully!');
} catch (error) {
dismiss(loadingId);
showError('Error', 'Failed to complete operation. Please try again.');
}
};
const showActionNotification = () => {
const notificationId = showWarning('Action Required', 'Do you want to proceed?', {
dismissAfter: 0,
buttons: [
{
name: 'Yes',
primary: true,
onClick: () => {
dismiss(notificationId);
showSuccess('Confirmed', 'Action confirmed.');
}
},
{
name: 'No',
onClick: () => {
dismiss(notificationId);
showInfo('Cancelled', 'Action cancelled.');
}
}
]
});
};
const clearAllNotifications = () => {
dispatch(dismissNotifications());
};
return (
<div style={{ padding: '20px', maxWidth: '600px', margin: '0 auto' }}>
<h1>Advanced Notification System</h1>
<form onSubmit={handleSubmit} style={{ marginBottom: '20px', padding: '20px', border: '1px solid #ddd', borderRadius: '8px' }}>
<div style={{ marginBottom: '16px' }}>
<label style={{ display: 'block', marginBottom: '4px', fontWeight: '500' }}>
Title *
</label>
<input
type="text"
name="title"
value={formData.title}
onChange={handleInputChange}
style={{
width: '100%',
padding: '8px',
border: '1px solid #ddd',
borderRadius: '4px',
boxSizing: 'border-box'
}}
required
/>
</div>
<div style={{ marginBottom: '16px' }}>
<label style={{ display: 'block', marginBottom: '4px', fontWeight: '500' }}>
Message *
</label>
<textarea
name="message"
value={formData.message}
onChange={handleInputChange}
rows={3}
style={{
width: '100%',
padding: '8px',
border: '1px solid #ddd',
borderRadius: '4px',
boxSizing: 'border-box',
resize: 'vertical'
}}
required
/>
</div>
<div style={{ marginBottom: '16px' }}>
<label style={{ display: 'block', marginBottom: '4px', fontWeight: '500' }}>
Status
</label>
<select
name="status"
value={formData.status}
onChange={handleInputChange}
style={{
width: '100%',
padding: '8px',
border: '1px solid #ddd',
borderRadius: '4px',
boxSizing: 'border-box'
}}
>
<option value="success">Success</option>
<option value="error">Error</option>
<option value="warning">Warning</option>
<option value="info">Info</option>
</select>
</div>
<button
type="submit"
style={{
width: '100%',
padding: '10px',
backgroundColor: '#007bff',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
fontSize: '16px'
}}
>
Show Notification
</button>
</form>
<div style={{ display: 'flex', flexDirection: 'column', gap: '10px' }}>
<button
onClick={simulateApiCall}
style={{
padding: '10px',
backgroundColor: '#28a745',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
}}
>
Simulate API Call
</button>
<button
onClick={showActionNotification}
style={{
padding: '10px',
backgroundColor: '#ffc107',
color: 'black',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
}}
>
Show Action Notification
</button>
<button
onClick={clearAllNotifications}
style={{
padding: '10px',
backgroundColor: '#dc3545',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
}}
>
Clear All Notifications
</button>
</div>
</div>
);
}
export default AdvancedNotificationSystem;
Update your App.jsx:
// src/App.jsx
import React from 'react';
import AdvancedNotificationSystem from './AdvancedNotificationSystem';
import './App.css';
function App() {
return (
<div className="App">
<AdvancedNotificationSystem />
</div>
);
}
export default App;
Update your store configuration for better setup:
// src/store/index.js
import { createStore, combineReducers, applyMiddleware } from 'redux';
import { reducer as notificationsReducer, setUpNotifications } from 'reapop';
import thunk from 'redux-thunk';
// Configure notifications
setUpNotifications({
defaultProps: {
position: 'top-right',
dismissible: true,
dismissAfter: 5000,
allowHTML: false
}
});
const rootReducer = combineReducers({
notifications: notificationsReducer
});
export const store = createStore(
rootReducer,
applyMiddleware(thunk)
);
Notifications not displaying: Ensure NotificationsSystem is rendered in your app and Provider wraps your application with the Redux store.
Redux store not configured: Make sure you've added the notifications reducer to your Redux store using combineReducers.
Actions not working: Ensure you're using useDispatch from react-redux to dispatch notification actions. The notify action creator must be imported from reapop.
Notifications not dismissing: Check the dismissAfter property. Set it to a number (milliseconds) for auto-dismissal, or 0 for persistent notifications. Use dismissible: true to allow manual dismissal.
Custom styling not working: Reapop allows custom notification components. You can override the default notification component by configuring it in setUpNotifications.
Multiple notifications stacking: Reapop handles multiple notifications automatically. They will stack based on the position setting. Use dismissNotifications() to clear all notifications at once.
Now that you have an advanced understanding of Reapop:
You've successfully integrated Reapop into your React application with Redux for advanced notification management. Reapop provides a scalable, Redux-based solution for displaying notifications with centralized state management and extensive customization options.
reapop
React Redux notifications
reapop tutorial
React notification system
reapop installation
React Redux toast
reapop example
React notification library
reapop setup
React Redux alerts
reapop customization
React notification hooks
reapop middleware
React notification state
reapop getting started
2026-01-20 00:35:03
We are familiar with frequency counting — counting elements in arrays or strings using hash maps or buckets. It’s a powerful tool, but as problems grow, relying solely on extra space can be limiting. That’s when the Two Pointer technique comes to the rescue: a space-efficient, intuitive way to traverse arrays or strings for many common problems.
In this article, we’ll explore what Two Pointer is, when to use it, types of problems it fits, and how to start practicing it today.
🔹 Frequency Count: The Warm-Up
Most beginner array problems use frequency counts:
vector<int> arr = {1,1,2,2,2,3};
unordered_map<int,int> freq;
for(int x : arr) freq[x]++; // Count occurrences
for(auto [val, count] : freq) {
cout << val << " appears " << count << " times\n";
}
This works great, but it uses extra space (O(n) for the map), and sometimes, we can solve problems in-place without extra memory using pointers.
That’s where Two Pointer technique shines.
🔹 What is Two Pointer Technique?
Two Pointer is using two indices instead of one to traverse an array, string, or linked list.
Why use it?
Think of it as moving pointers smartly based on conditions, instead of blindly iterating every element.
🔹 When to Think Two Pointer?
Ask yourself these questions:
✅ Is the problem on array / string / list?
✅ Is it sorted or can it be sorted?
✅ Are you asked about pairs, ranges, windows, or symmetry?
✅ Can you avoid nested loops with clever pointer movement?
If most answers are YES, Two Pointer is likely the right approach.
Keywords to spot:
“Two numbers sum to K” → left/right pointers
“Palindrome” → left/right pointers
“Remove duplicates” → slow/fast pointer
“Longest substring” → sliding window
“Merge arrays” → left/right pointers
1️⃣ Opposite Direction (Left ↔ Right)
Pattern:
L → ← R
Used for:
Typical problems:
Mental Rule:
Example:
int l = 0, r = n-1;
while(l < r) {
int sum = arr[l] + arr[r];
if(sum == target) return true;
else if(sum < target) l++;
else r--;
}
2️⃣ Same Direction (Slow & Fast)
Pattern:
slow →
fast → →
Used for:
Typical problems:
Mental Rule:
Example:
int slow = 0;
for(int fast = 0; fast < n; fast++) {
if(arr[fast] != val) arr[slow++] = arr[fast];
}
3️⃣ Sliding Window (Expandable & Shrinkable)
Pattern:
L → → → R
Used for:
Mental Rule:
🔹How to Identify Two Pointer Problems Quickly
Checklist:
If 3+ YES, it’s likely a Two Pointer problem.
🔹Beginner Mistakes to Avoid
❌ Using pointers on unsorted arrays blindly
❌ Moving both pointers without logic
❌ Forgetting while(l < r) condition
❌ Confusing sliding window with opposite pointer approach
🔹How to Practice Effectively
This reinforces logic, not just syntax.
🔹 Starter Practice Set
Try these in order:
🌱 Final Thought
Two Pointer isn’t about syntax.
It’s about smart pointer movement:
“If condition improves → move this pointer
If condition worsens → move the other pointer”
Master this, and many array problems become simple, elegant, and efficient.
2026-01-20 00:32:46
Hi everyone!
I’ve been working on a library called processes. It’s designed to simplify and "robustify" periodic routines.
Description: You create a Process made out of Tasks. Tasks can have dependencies and can run in parallel. If one fails, non-dependent Tasks continue to run. If set, en email notification is sent on failed Tasks giving details of the error and all Tasks that could not be executed.
Code example:
from datetime import date
from processes import Process, Task, TaskDependency, HTMLSMTPHandler
# 1. Setup Email Alerts (Optional)
smtp_handler = HTMLSMTPHandler(
('smtp_server', 587), '[email protected]', ['[email protected]', '[email protected]'],
use_tls=True, credentials=('user', 'pass')
)
# 2. If necessary, create wrappers for your Tasks.
def get_previous_working_day():
return date(2025, 12, 30)
def indep_task():
return "foo"
def search_and_sum_csv(t: date):
return 10
def sum_data_from_csv_and_x(x, a=1, b=2):
return x + a + b
# 3. Create the Task Graph (order is irrelevant, that is handled by Process)
tasks = [
Task("t-1", "etl.log", get_previous_working_day),
Task("intependent", "indep.log", indep_task, html_mail_handler=smtp_handler), # This task will send email on failure
Task("sum_csv", "etl.log", search_and_sum_csv,
dependencies= [
TaskDependency("t-1",
use_result_as_additional_args=True) # Adds result of t-1 task to search_and_sum_csv function as aditional args
]
),
Task("sum_x_and_csv", "etl.log", sum_data_from_csv_and_x,
args = (10,), kwargs = {"b": 100},
dependencies=[
TaskDependency("sum_csv",
use_result_as_additional_kwargs=True,
additional_kwarg_name="a")
]
)
]
# 4. Run the Process
with Process(tasks) as process: # Context Manager ensures correct disposal of loggers
process_result = process.run() # To enable parallelization use .run(parallel=True)
I’ve spent the last few days setting up a "pro" workflow (uv, ruff, mypy, pytest, and GitHub Actions with Trusted Publishers), and I’ve finally hit PyPI.
I’m looking for feedback on:
Repo: https://github.com/oliverm91/processes
PyPI: https://pypi.org/project/processes/
Thanks in advance for any roasting or advice you can give!