Best Practices and Anti-Patterns
Level: Beginner
- Component naming and file organization
- Folder structure for scalability
- Avoiding inline functions and object recreation
- Proper key usage in lists
- State placement and lifting
- Prop drilling alternatives
- Performance optimization patterns
- Code review checklist for SMS
Why This Matters
Best Practices and Anti-Patterns is part of building maintainable React applications. You will use it when creating student dashboards, forms, tables, API-connected screens, routing flows, and reusable UI components.
Learn to write React code that's maintainable, performant, and bug-free.
The Problem
Beginners often write React code that works for a small demo but becomes difficult when data, forms, API calls, and reusable components grow. This lesson explains Best Practices and Anti-Patterns in a way that helps you build predictable UI for real .NET Web API projects.
Component Design
✓ Keep Components Small
// ❌ Too large — 300 lines in one component
function StudentDashboard() {
// Student list, marks, attendance, fees, actions all here
}
// ✓ Better — split into smaller pieces
function StudentDashboard() {
return (
<>
<StudentInfo />
<StudentMarks />
<StudentAttendance />
<StudentFees />
</>
);
}
✓ Props Over Drilling
// ❌ Prop drilling
<SchoolContext>
<ClassList students={students} />
</SchoolContext>
// ✓ Use Context
<SchoolProvider>
<ClassList />
</SchoolProvider>
✓ Default Props
// ❌ Manual defaults in function
function StudentCard({ student }) {
const name = student?.name || 'Unknown';
return <h3>{name}</h3>;
}
// ✓ Default parameters
function StudentCard({ student = {} }) {
return <h3>{student.name || 'Unknown'}</h3>;
}
Performance
✓ Memoize Components
// ❌ Re-renders even if props unchanged
function StudentCard({ student }) {
return <div>{student.name}</div>;
}
// ✓ Memoized — only re-renders if props change
const StudentCard = React.memo(function StudentCard({ student }) {
return <div>{student.name}</div>;
});
✓ Key in Lists
// ❌ Index as key (breaks if list reorders)
{students.map((s, index) => (
<li key={index}>{s.name}</li>
))}
// ✓ Unique ID as key
{students.map(s => (
<li key={s.id}>{s.name}</li>
))}
✓ Lazy Load Components
const StudentDetail = React.lazy(() => import('./StudentDetail'));
function App() {
return (
<Routes>
<Route
path="/students/:id"
element={
<Suspense fallback={<Loading />}>
<StudentDetail />
</Suspense>
}
/>
</Routes>
);
}
Code Organization
✓ Separate Concerns
// ❌ API logic in component
function StudentList() {
const [students, setStudents] = useState([]);
useEffect(() => {
fetch('/api/students')
.then(r => r.json())
.then(data => setStudents(data));
}, []);
return students.map(s => <StudentCard key={s.id} student={s} />);
}
// ✓ Extract API logic
import { useFetchStudents } from './hooks';
function StudentList() {
const students = useFetchStudents();
return students.map(s => <StudentCard key={s.id} student={s} />);
}
✓ Custom Hooks for Logic
// ❌ Complex state in component
function StudentForm() {
const [form, setForm] = useState({});
const [errors, setErrors] = useState({});
const handleChange = () => { /* ... */ };
const handleSubmit = () => { /* ... */ };
const validate = () => { /* ... */ };
return <form onSubmit={handleSubmit}>{/* ... */}</form>;
}
// ✓ Extract to custom hook
function useStudentForm() {
const [form, setForm] = useState({});
const [errors, setErrors] = useState({});
const handleChange = () => { /* ... */ };
const handleSubmit = () => { /* ... */ };
return { form, errors, handleChange, handleSubmit };
}
function StudentForm() {
const { form, handleChange, handleSubmit } = useStudentForm();
return <form onSubmit={handleSubmit}>{/* ... */}</form>;
}
Error Handling
✓ Always Handle Loading/Error States
// ❌ No loading state
function StudentList() {
const [students, setStudents] = useState([]);
useEffect(() => {
fetch('/api/students').then(r => r.json()).then(setStudents);
}, []);
return students.map(s => <StudentCard key={s.id} student={s} />);
}
// ✓ Handle all states
function StudentList() {
const [students, setStudents] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch('/api/students')
.then(r => r.json())
.then(data => { setStudents(data); setLoading(false); })
.catch(err => { setError(err); setLoading(false); });
}, []);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error}</p>;
return students.map(s => <StudentCard key={s.id} student={s} />);
}
State Management
✓ Local State by Default
// ❌ Global state for everything
const [searchQuery, setSearchQuery] = useContext(GlobalState);
// ✓ Local state for temporary data
function StudentSearch() {
const [searchQuery, setSearchQuery] = useState('');
return <input value={searchQuery} onChange={e => setSearchQuery(e.target.value)} />;
}
✓ useReducer for Complex Logic
// ❌ Multiple useState for related data
function StudentManager() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [className, setClassName] = useState('');
}
// ✓ useReducer
function StudentManager() {
const [form, dispatch] = useReducer(formReducer, initialState);
}
Naming Conventions
✓ Clear, Semantic Names
// ❌ Unclear
function D({ d }) {
return <div onClick={() => f(d.id)}>{d.n}</div>;
}
// ✓ Clear
function StudentCard({ student }) {
return <div onClick={() => handleDelete(student.id)}>{student.name}</div>;
}
✓ Function Naming
// ❌ Unclear
const h = () => { /* ... */ };
// ✓ Clear
const handleStudentDelete = () => { /* ... */ };
const validateForm = () => { /* ... */ };
const fetchStudents = () => { /* ... */ };
Testing
✓ Write Testable Components
// ❌ Hard to test — API call inside
function StudentList() {
useEffect(() => {
fetch('/api/students').then(/* ... */);
}, []);
}
// ✓ Easy to test — pass data via props
function StudentList({ students = [] }) {
return students.map(s => <StudentCard key={s.id} student={s} />);
}
Security
✓ Sanitize User Input
// ❌ XSS vulnerability
const comment = '<img src=x onerror=alert("XSS")>';
<div>{comment}</div>
// ✓ React escapes by default
<div>{userInput}</div>
// For HTML content, use DOMPurify
import DOMPurify from 'dompurify';
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(html) }} />
✓ Never Expose Secrets
// ❌ Secrets in frontend code
const API_KEY = 'sk-secret-key-12345';
// ✓ Keep secrets on backend
const response = await fetch('/api/protected-endpoint');
Common Anti-Patterns
❌ Mutating Props
// ❌ Wrong
function StudentCard({ student }) {
student.name = "Changed";
return <div>{student.name}</div>;
}
❌ Direct DOM Manipulation
// ❌ Wrong
function StudentList() {
useEffect(() => {
document.getElementById('list').innerHTML = '<li>Student 1</li>';
}, []);
return <ul id="list"></ul>;
}
// ✓ Use React state
function StudentList() {
return (
<ul>
{students.map(s => <li key={s.id}>{s.name}</li>)}
</ul>
);
}
❌ Async in useEffect without Cleanup
// ❌ Wrong — missing cleanup
useEffect(() => {
const interval = setInterval(() => {
// ...
}, 1000);
}, []);
// ✓ Correct
useEffect(() => {
const interval = setInterval(() => {
// ...
}, 1000);
return () => clearInterval(interval);
}, []);
File Structure
src/
├── components/
│ ├── StudentCard.jsx
│ ├── StudentList.jsx
│ ├── StudentForm.jsx
├── pages/
│ ├── StudentListPage.jsx
│ ├── StudentDetailPage.jsx
├── hooks/
│ ├── useFetch.js
│ ├── useForm.js
├── services/
│ ├── studentService.js
│ ├── teacherService.js
├── contexts/
│ ├── AuthContext.js
│ ├── SchoolContext.js
├── App.jsx
├── index.jsx
Key Takeaways
- Small, focused components
- Handle loading and errors
- Use custom hooks for logic
- Memoize when needed
- Keep state local
- Clear naming
- Secure code
- Testable design
- Mutate props or state directly
- Call hooks conditionally
- Expose API keys in frontend
- Skip error handling
- Create giant components
- Use array index as key in lists
Before committing:
- Components are small and focused
- Error states handled
- Loading states shown
- No prop drilling (< 2 levels)
- Performance optimized
- Accessible (semantic HTML)
- Consistent naming
Use ChatGPT, Claude, or Copilot to go deeper on React Best Practices. Try these prompts:
"What's the difference between good and bad component design?""When should you use memo() vs. useCallback()?""What's an anti-pattern you should avoid?""Quiz me on React best practices"
💡 Tip: After reading this article, paste your own code into AI and ask "What could go wrong here and why?" — fastest way to find edge cases and deepen understanding.
Quick Definitions
- Best Practices and Anti-Patterns - The main React concept explained in this lesson.
- Component - A reusable function that returns UI.
- Props/state/effects - Core React ideas used to pass data, remember data, and run side effects.
- Real project usage - How this appears in forms, dashboards, routes, and API-connected pages.
Common Mistakes
- Copying React code without understanding data flow
- Mutating arrays or objects directly instead of creating new values
- Forgetting keys, dependencies, loading states, or error states where needed
- Putting too much logic in one component
- Not testing the screen with realistic School Management System data
Practice Task
Create a small React example using Best Practices and Anti-Patterns. Keep it focused on one School Management System screen.
Suggested practice:
- Build a small component or page for students, attendance, marks, or fees.
- Pass realistic data into the component.
- Add one success state and one empty/error state where relevant.
- Explain the data flow in your own words.
- Rebuild the same example once without looking at the article.
Quick Revision
| Question | Answer |
|---|---|
| What is the main idea? | Understand and apply Best Practices and Anti-Patterns in React. |
| Where is it used? | Student dashboards, forms, tables, routes, and API-connected screens. |
| What should beginners focus on? | Clear components, predictable data flow, and small examples. |
| What is the best debugging habit? | Check props, state, render output, and browser console step by step. |
Best Practices and Anti-Patterns is a React concept used to build clear, reusable, and predictable user interfaces. I would explain the problem it solves, show a small component example, and mention a common mistake beginners should avoid.
It is used in screens like student lists, admission forms, attendance dashboards, marks reports, routing pages, and API-connected admin panels.