import React, { useState, useEffect, useCallback, useMemo } from 'react';
// Test component with various React patterns and potential issues
interface UserProps {
id: number;
name: string;
email: string;
isActive: boolean;
metadata?: Record<string, any>;
}
interface ComponentProps {
users: UserProps[];
onUserSelect: (user: UserProps) => void;
theme: {
primaryColor: string;
backgroundColor: string;
};
config: {
pageSize: number;
sortBy: string;
};
}
// Component with props drilling issue
const UserCard: React.FC<{
user: UserProps;
theme: ComponentProps['theme'];
config: ComponentProps['config'];
onSelect: (user: UserProps) => void;
}> = ({ user, theme, config, onSelect }) => {
return (
<div style={{ backgroundColor: theme.backgroundColor }}>
<UserDetails user={user} theme={theme} config={config} />
<button onClick={() => onSelect(user)}>Select</button>
</div>
);
};
// Another level of props drilling
const UserDetails: React.FC<{
user: UserProps;
theme: ComponentProps['theme'];
config: ComponentProps['config'];
}> = ({ user, theme, config }) => {
return (
<div style={{ color: theme.primaryColor }}>
<h3>{user.name}</h3>
<p>{user.email}</p>
{config.sortBy === 'name' && <span>Sorted by name</span>}
</div>
);
};
// Main component with various hook issues
const UserList: React.FC<ComponentProps> = ({ users, onUserSelect, theme, config }) => {
const [selectedUser, setSelectedUser] = useState<UserProps | null>(null);
const [searchTerm, setSearchTerm] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [data, setData] = useState<any[]>([]);
// Hook violation: useEffect without dependency array
useEffect(() => {
console.log('This will run on every render!');
});
// Hook violation: missing dependency
useEffect(() => {
if (selectedUser) {
console.log(`Selected user: ${selectedUser.name}`);
}
}, []); // Missing selectedUser in dependencies
// Hook violation: unnecessary dependency
useEffect(() => {
setIsLoading(true);
// Simulate API call
setTimeout(() => {
setIsLoading(false);
}, 1000);
}, [searchTerm, theme]); // theme is unnecessary dependency
// Performance issue: missing useMemo for expensive calculation
const expensiveCalculation = () => {
return users.reduce((acc, user) => {
return acc + user.name.length + user.email.length;
}, 0);
};
// Performance issue: object created in render
const handleUserSelect = (user: UserProps) => {
setSelectedUser(user);
onUserSelect(user);
};
// Good use of useMemo
const filteredUsers = useMemo(() => {
return users.filter(user =>
user.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
user.email.toLowerCase().includes(searchTerm.toLowerCase())
);
}, [users, searchTerm]);
// Performance issue: useCallback with object dependency
const handleSearch = useCallback((term: string) => {
setSearchTerm(term);
}, [theme]); // theme is object dependency that might cause issues
// Conditional hook usage (violation)
if (isLoading) {
const [loadingState] = useState('loading'); // Hook called conditionally
return <div>Loading...</div>;
}
return (
<div>
<input
type="text"
value={searchTerm}
onChange={(e) => handleSearch(e.target.value)}
placeholder="Search users..."
/>
<div>Total characters: {expensiveCalculation()}</div>
{filteredUsers.map(user => (
<UserCard
key={user.id}
user={user}
theme={theme}
config={config}
onSelect={handleUserSelect}
/>
))}
{selectedUser && (
<div>
<h2>Selected User</h2>
<UserDetails user={selectedUser} theme={theme} config={config} />
</div>
)}
</div>
);
};
// Class component (should suggest conversion to functional)
class LegacyComponent extends React.Component<{ title: string }> {
state = {
count: 0
};
handleClick = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<h1>{this.props.title}</h1>
<p>Count: {this.state.count}</p>
<button onClick={this.handleClick}>Increment</button>
</div>
);
}
}
// Component with high complexity
const ComplexComponent: React.FC<{ items: any[] }> = ({ items }) => {
const [filter, setFilter] = useState('');
const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('asc');
const [groupBy, setGroupBy] = useState<string>('');
const processedItems = useMemo(() => {
let result = items;
// Multiple nested conditions and loops
if (filter) {
result = result.filter(item => {
if (typeof item === 'string') {
return item.includes(filter);
} else if (typeof item === 'object') {
return Object.values(item).some(value =>
typeof value === 'string' && value.includes(filter)
);
}
return false;
});
}
if (sortOrder) {
result = result.sort((a, b) => {
const aValue = typeof a === 'string' ? a : JSON.stringify(a);
const bValue = typeof b === 'string' ? b : JSON.stringify(b);
if (sortOrder === 'asc') {
return aValue.localeCompare(bValue);
} else {
return bValue.localeCompare(aValue);
}
});
}
if (groupBy) {
const grouped = result.reduce((acc, item) => {
const key = typeof item === 'object' ? item[groupBy] : 'default';
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(item);
return acc;
}, {} as Record<string, any[]>);
return Object.entries(grouped).map(([key, values]) => ({
group: key,
items: values
}));
}
return result.map(item => ({ group: 'default', items: [item] }));
}, [items, filter, sortOrder, groupBy]);
return (
<div>
<div>
<input
value={filter}
onChange={(e) => setFilter(e.target.value)}
placeholder="Filter..."
/>
<select value={sortOrder} onChange={(e) => setSortOrder(e.target.value as 'asc' | 'desc')}>
<option value="asc">Ascending</option>
<option value="desc">Descending</option>
</select>
<input
value={groupBy}
onChange={(e) => setGroupBy(e.target.value)}
placeholder="Group by field..."
/>
</div>
{processedItems.map((group, index) => (
<div key={index}>
<h3>{group.group}</h3>
{group.items.map((item, itemIndex) => (
<div key={itemIndex}>
{typeof item === 'string' ? item : JSON.stringify(item)}
</div>
))}
</div>
))}
</div>
);
};
export { UserList, LegacyComponent, ComplexComponent };