dev.rean.me
react-js

ReactJS Tips and Tricks with Examples

Learn essential ReactJS tips and tricks with simple English explanations, bad code vs good code examples, performance optimization, and best practices.

2026-08-27 · 9 min read

Share:

ReactJS Tips & Tricks — Best Practice with Examples

Hello friend! Today we share best ReactJS tips and tricks. These tips help you write clean code, avoid common bug, and make React app run faster!

If you are new to ReactJS, read our step-by-step previous lessons first:

We explain in simple way with Bad Code ❌ vs Good Code ✅. Easy to understand!


1. Use Functional Component (Not Class Component)

Modern React use Functional Component with Hooks. Do not use old Class Component anymore. It is easier to read and write less code!

Bad (Old Class Component):

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}!</h1>;
  }
}

Good (Functional Component):

function Welcome({ name }) {
  return <h1>Hello, {name}!</h1>;
}

💡 Tip: Want to learn more about components and props? Read our full guide: → Functional and Class Component with Props in ReactJS


2. Functional State Update — setCount(prev => prev + 1)

When new state depend on previous state, always use functional update. If you pass value directly, it can have bug when state update multiple times quickly!

Bad:

const handleClick = () => {
  setCount(count + 1);
  setCount(count + 1); // ⚠️ Bug! Count only increase by 1, not 2!
};

Good:

const handleClick = () => {
  setCount(prev => prev + 1);
  setCount(prev => prev + 1); // ✅ Work correct! Count increase by 2!
};

💡 Tip: Want deep dive into state management? Check out: → ReactJS State Management with useState


3. Never Mutate State Directly

In React, state is immutable (do not change original object/array directly). Always make a new copy using spread operator (...)!

Bad (Direct Mutation):

const [user, setUser] = useState({ name: 'Rean', age: 20 });

// ❌ React will NOT re-render because object reference not change!
user.age = 21;
setUser(user);

Good (Spread Operator):

const [user, setUser] = useState({ name: 'Rean', age: 20 });

// ✅ Create new object copy — React re-render properly!
setUser({ ...user, age: 21 });

💡 Tip: For Array, use [...items, newItem] to add, or .filter() to delete. Never use .push() or .splice() directly on state!


4. Always Use Unique key in .map() List

When render list with .map(), React need unique key prop to identify each item. Do not use array index i as key if list item order can change!

Bad (Use Index as Key):

{users.map((user, index) => (
  <li key={index}>{user.name}</li>
))}

Good (Use Unique ID as Key):

{users.map(user => (
  <li key={user.id}>{user.name}</li>
))}

⚠️ Warning: Using array index as key can cause wrong UI animation and form input bug when list item sorted or deleted!


5. Be Careful with && Conditional Rendering

Using && with numbers can print 0 on screen if number is 0!

Bad:

const itemCount = 0;

return (
  <div>
    {/* ❌ This will print "0" on screen! Because 0 is falsy but React render 0! */}
    {itemCount && <p>You have {itemCount} items</p>}
  </div>
);

Good:

const itemCount = 0;

return (
  <div>
    {/* ✅ Explicit check with > 0 or Ternary operator */}
    {itemCount > 0 && <p>You have {itemCount} items</p>}
    
    {/* Or ternary: */}
    {itemCount > 0 ? <p>You have {itemCount} items</p> : null}
  </div>
);

6. Cleanup useEffect Timers and Subscriptions

If you use setInterval, setTimeout, or add event listener inside useEffect, always return cleanup function. Otherwise you get memory leak!

Bad (No Cleanup):

useEffect(() => {
  const timer = setInterval(() => {
    console.log('Tick');
  }, 1000);
  // ❌ Memory leak! Timer keep running even when component unmounted!
}, []);

Good (With Cleanup):

useEffect(() => {
  const timer = setInterval(() => {
    console.log('Tick');
  }, 1000);

  // ✅ Clean up timer when component unmount!
  return () => clearInterval(timer);
}, []);

7. Custom Hooks — Reuse Your Logic

If you write same useEffect or state logic in multiple components, extract it into a Custom Hook! Custom Hook name must start with use.

Example (Custom Hook useFetch):

// hooks/useFetch.js
function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch(url)
      .then(res => res.json())
      .then(data => {
        setData(data);
        setLoading(false);
      });
  }, [url]);

  return { data, loading };
}

// Use inside any component:
function UserList() {
  const { data, loading } = useFetch('/api/users');
  if (loading) return <p>Loading...</p>;
  return <div>{/* render data */}</div>;
}

💡 Tip: Custom Hooks make your UI component very clean and short!


8. Handle Loading & Error States in API Call

Always handle Loading, Error, and Data states when fetch data from API. Don't leave user on blank screen!

Good Practice:

function StudentList() {
  const [students, setStudents] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetch('https://api.example.com/students')
      .then(res => {
        if (!res.ok) throw new Error('Failed to fetch data');
        return res.json();
      })
      .then(data => {
        setStudents(data);
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  }, []);

  if (loading) return <div>⏳ Loading students...</div>;
  if (error) return <div>❌ Error: {error}</div>;

  return (
    <ul>
      {students.map(s => <li key={s.id}>{s.name}</li>)}
    </ul>
  );
}

9. Destructure Props for Cleaner Code

Pass props directly and destructure in component parameter. Don't repeat props.name, props.age, props.email everywhere!

Bad:

function UserCard(props) {
  return (
    <div>
      <h3>{props.name}</h3>
      <p>{props.email}</p>
      <p>{props.role}</p>
    </div>
  );
}

Good:

function UserCard({ name, email, role = 'User' }) {
  return (
    <div>
      <h3>{name}</h3>
      <p>{email}</p>
      <p>{role}</p>
    </div>
  );
}

💡 Tip: You can also set default value directly: role = 'User'.


10. Use Fragment <> to Avoid Extra <div>

React component must return single parent element. Instead of adding extra <div> wrappers that mess up CSS flexbox/grid, use React Fragment <> ... </>!

Bad (Extra unnecessary DOM node):

return (
  <div className="wrapper">
    <Header />
    <MainContent />
  </div>
);

Good (Clean DOM):

return (
  <>
    <Header />
    <MainContent />
  </>
);

💡 Tip: Read our detailed guide on Fragment: → ReactJS Fragment Explained with Code Examples


11. Keep State Close to Where it is Used

Don't put all state in root component (App.jsx) if only small child component need it!

Bad: Putting search input state in App component when only SearchBar component use it. ✅ Good: Put search input state inside SearchBar component directly.

💡 Tip: Lift state up to parent ONLY when multiple sibling components need to share same state!


12. Don't Store Derived State

If value can be calculated from existing state or props, do not store it in a new state!

Bad:

const [firstName, setFirstName] = useState('Rean');
const [lastName, setLastName] = useState('Code');
const [fullName, setFullName] = useState('Rean Code'); // ❌ Unnecessary state!

Good:

const [firstName, setFirstName] = useState('Rean');
const [lastName, setLastName] = useState('Code');

// ✅ Calculate directly! Automatically update when firstName or lastName change!
const fullName = `${firstName} ${lastName}`;

13. Controlled Input for Forms

For form inputs in React, use value and onChange to make input state controlled by React.

Good Example:

function LoginForm() {
  const [email, setEmail] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault(); // Stop browser reload!
    console.log('Submitting email:', email);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Enter email"
      />
      <button type="submit">Login</button>
    </form>
  );
}

💡 Tip: Learn more about forms and event handling: → Basic Event Handling with Form in ReactJS


14. Never Put Secret API Keys in Frontend Code

React code runs inside user browser. Anyone can open Browser DevTools (F12) and see your API secret keys!

Bad:

const STRIPE_SECRET_KEY = 'sk_test_123456789'; // ❌ NEVER DO THIS!

Good:

  • Use public key only on frontend (NEXT_PUBLIC_... or VITE_...).
  • Put secret API keys on backend server (Node.js, Next.js API Route, Laravel, etc.)!

15. Optimize Only When Needed (useMemo & useCallback)

Do NOT wrap every function with useCallback or every value with useMemo. Overusing them makes code harder to read and slows down memory performance!

💡 Rule of Thumb:

  • Use useMemo ONLY for expensive calculation (like sorting 10,000 items).
  • Use useCallback ONLY when passing function to child component wrapped with React.memo().
  • First write simple clean code. Optimize only when you notice performance lag!

Summary — Quick Checklist

TipDescriptionBenefit
1. Functional ComponentUse function + HooksModern, clean code
2. setCount(prev => prev + 1)Functional state updateAvoid async state bug
3. Immutable StateUse ...spread copyTrigger proper re-render
4. Unique keyUse user.id not indexPrevents list UI bugs
5. Safe &&Use count > 0 && ...Avoid printing 0 on screen
6. Cleanup useEffectReturn () => clearInterval()Avoid memory leak
7. Custom HooksuseFetch(), useAuth()Reuse logic easily
8. Loading & ErrorHandle loading, error, dataGreat UX for user
9. Destructure Propsfunction({ name, age })Less repetitive code
10. Fragment <>Return <> ... </>No useless <div> in DOM

📚 Read Previous ReactJS Tutorials

If you want to learn more about ReactJS, check out all our previous step-by-step lessons:

Happy coding with ReactJS! 🎉

← Back to react-js
Share: