Enhanced React useEffect and useLayoutEffect hooks with smart dependency tracking, debugging tools, and automatic optimization
npm install react-smart-effectš Enhanced React useEffect and useLayoutEffect hooks with smart dependency tracking, debugging tools, and automatic optimization.
- šÆ Smart dependency tracking with deep comparison support
- š Advanced debugging with dependency change logging
- š Dependency analysis to detect potential issues
- ā” Automatic optimization to prevent unnecessary re-renders
- š ļø DevTools integration with real-time effect monitoring
- š§ Babel & Vite plugins for build-time analysis
- š Effect visualization and dependency graphs
- šŖ TypeScript support with full type safety
``bash`
npm install react-smart-effect
`tsx
import { useSmartEffect } from 'react-smart-effect';
function MyComponent() {
const [count, setCount] = useState(0);
const [user, setUser] = useState({ name: 'John', age: 30 });
// Basic usage - enhanced useEffect
useSmartEffect(() => {
console.log('Count changed:', count);
}, [count]);
// Skip first render
useSmartEffect(() => {
console.log('This runs only after first render');
}, [count], { skipFirstRender: true });
// Deep comparison for objects/arrays
useSmartEffect(() => {
console.log('User changed (deep comparison):', user);
}, [user], { deepCompare: true });
// Debug mode with dependency analysis
useSmartEffect(() => {
fetchUserData(user.id);
}, [user], { debug: true });
return
API Reference
$3
Enhanced version of
useEffect with additional features.Parameters:
-
effect: Effect callback function
- deps: Dependency array (optional)
- options: Configuration object (optional)Options:
`tsx
interface UseSmartEffectOptions {
/* Skip execution on first render /
skipFirstRender?: boolean;
/* Enable debug logging /
debug?: boolean;
/* Use useLayoutEffect instead of useEffect /
mode?: 'effect' | 'layoutEffect';
/* Enable deep comparison for objects and arrays /
deepCompare?: boolean;
/* Custom comparison function /
compareFunction?: (prev: any[], next: any[]) => boolean;
/* Unique identifier for this effect (for debugging) /
id?: string;
}
`$3
`tsx
// Deep comparison enabled by default
useDeepEffect(effect, deps, options);// Debug mode enabled by default
useDebugEffect(effect, deps, options);
// useLayoutEffect mode by default
useSmartLayoutEffect(effect, deps, options);
`Advanced Usage
$3
The hook automatically analyzes your dependencies and warns about potential issues:
`tsx
function Component() {
const [items, setItems] = useState([]);
useSmartEffect(() => {
// This will warn about the object literal
processData(items);
}, [items, { processImmediate: true }], { debug: true });
// Warning: Object at index 1 - consider useMemo
}
`$3
Prevent unnecessary re-renders when using objects or arrays:
`tsx
function Component() {
const [filters, setFilters] = useState({ category: 'all', status: 'active' });
// Without deep comparison - runs on every render if filters object is recreated
useEffect(() => {
fetchData(filters);
}, [filters]); // With deep comparison - only runs when filter values actually change
useDeepEffect(() => {
fetchData(filters);
}, [filters]);
}
`$3
Use your own comparison logic:
`tsx
function Component() {
const [user, setUser] = useState({ name: 'John', lastLogin: Date.now() });
useSmartEffect(() => {
updateUserProfile(user);
}, [user], {
compareFunction: (prev, next) => {
// Only compare name, ignore lastLogin changes
return prev[0]?.name === next[0]?.name;
}
});
}
`$3
Monitor your effects in real-time:
`tsx
import { generateEffectGraph, enableDevTools } from 'react-smart-effect';// Enable DevTools (automatically enabled in development)
enableDevTools(true);
function App() {
// Your effects will now be tracked
useSmartEffect(() => {
// Effect logic
}, [dep1, dep2], { id: 'my-effect' });
// Generate visual graph in console
const handleShowGraph = () => {
generateEffectGraph();
};
return (
);
}
`Build-Time Analysis
$3
Add to your
.babelrc:`json
{
"plugins": [
["react-smart-effect/babel", {
"autoFix": false,
"warnOnly": true
}]
]
}
`$3
Add to your
vite.config.ts:`tsx
import { defineConfig } from 'vite';
import { vitePluginSmartEffect } from 'react-smart-effect/vite';export default defineConfig({
plugins: [
vitePluginSmartEffect({
warnOnly: true,
autoFix: false
})
]
});
`The plugins will analyze your code and warn about:
- Object/array literals in dependencies (suggest
useMemo)
- Function expressions in dependencies (suggest useCallback)
- Missing dependencies
- Redundant dependenciesDevTools Panel
The package includes a DevTools integration that shows:
- All active effects and their states
- Dependency changes over time
- Effect execution timeline
- Performance metrics
$3
When DevTools are enabled, you can use these console commands:
`javascript
// Show all effect reports
__REACT_SMART_EFFECT_DEVTOOLS__.getReports()// Show specific effect
__REACT_SMART_EFFECT_DEVTOOLS__.getReport('effect-id')
// Clear all reports
__REACT_SMART_EFFECT_DEVTOOLS__.clearReports()
// Generate visual graph
__REACT_SMART_EFFECT_DEVTOOLS__.generateGraph()
`Utility Functions
$3
Analyze a dependency array and categorize dependencies:
`tsx
import { analyzeDeps } from 'react-smart-effect';const analysis = analyzeDeps([1, {}, [], () => {}]);
console.log(analysis);
// {
// primitives: [1],
// objects: [{}, []],
// functions: [Function],
// potentiallyMissing: ['Object at index 1 - consider useMemo', ...]
// }
`$3
Deep comparison function for dependency arrays:
`tsx
import { deepCompareDeps } from 'react-smart-effect';const same = deepCompareDeps([{ a: 1 }], [{ a: 1 }]); // true
const different = deepCompareDeps([{ a: 1 }], [{ a: 2 }]); // false
`Examples
$3
`tsx
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(false); // Only refetch when userId actually changes, not on every render
useSmartEffect(() => {
setLoading(true);
fetchUser(userId).then(setUser).finally(() => setLoading(false));
}, [userId], {
debug: true,
id: 'fetch-user'
});
if (loading) return
Loading...;
return {user?.name};
}
`$3
`tsx
function FilteredList({ items }) {
const [filters, setFilters] = useState({
category: 'all',
sortBy: 'name',
ascending: true
});
const [filteredItems, setFilteredItems] = useState([]); // Use deep comparison to avoid unnecessary filtering
useDeepEffect(() => {
const filtered = applyFilters(items, filters);
setFilteredItems(filtered);
}, [items, filters], {
debug: true,
id: 'filter-items'
});
return (
{/ Filter controls /}
{filteredItems.map(item => )}
);
}
`$3
`tsx
function SearchResults({ query }) {
const [results, setResults] = useState([]); // Don't search on mount, only when user types
useSmartEffect(() => {
if (query.trim()) {
searchAPI(query).then(setResults);
}
}, [query], {
skipFirstRender: true,
debug: true
});
return
{/ Render results /};
}
`Performance Tips
1. Use
deepCompare: true for object/array dependencies
2. Wrap objects with useMemo when passing them as dependencies
3. Wrap functions with useCallback when passing them as dependencies
4. Enable debug: true during development to catch issues
5. Use the Babel/Vite plugins for build-time analysisMigration from useEffect
Replace your existing
useEffect calls:`tsx
// Before
useEffect(() => {
// effect
}, [dep1, dep2]);// After
useSmartEffect(() => {
// effect
}, [dep1, dep2]);
// With options
useSmartEffect(() => {
// effect
}, [dep1, dep2], {
deepCompare: true,
debug: process.env.NODE_ENV === 'development'
});
``The package is written in TypeScript and includes full type definitions. All hooks and utilities are fully typed.
Contributions are welcome! Please feel free to submit a Pull Request.
MIT Ā© [saif eddine keraa]