DEV Community

Cover image for Mistakes That Destroy Your Codebase!
RG Global x htmllessons
RG Global x htmllessons

Posted on

Mistakes That Destroy Your Codebase!

Tip/Mistake 1: Use export const Instead of export default

Many developers use export default because it seems obvious, but it has drawbacks:

  • The function name is fixed and hard to rename during import.
  • In large codebases, this can lead to errors.

Advantage of export const:

Each component has a clear, unique name, which makes it easier to find and debug.

Example with export default:

export default function getData() {
  return fetch('/api/data');
}

Enter fullscreen mode Exit fullscreen mode

Problem:

You must use the exact name when importing:

import getData from './getData'; // Cannot rename without extra work

Enter fullscreen mode Exit fullscreen mode

Example with export const:

export const getData = () => fetch('/api/data');

Enter fullscreen mode Exit fullscreen mode

Advantage:

You can import it by name and even rename it if needed:

import { getData } from './getData';

Enter fullscreen mode Exit fullscreen mode

Tip/Mistake 2: Using useFormStatus to Improve UX for Post Creation

Manually handling form submission state with useState can add extra work. React’s useFormStatus hook simplifies tracking form submission without extra code.

Example:

import { useFormStatus } from 'react-dom';

function SubmitButton() {
  const { pending } = useFormStatus();

  return (
    <button type="submit" disabled={pending}>
      {pending ? 'Creating...' : 'Publish'}
    </button>
  );
}

function CreatePostForm() {
  return (
    <form action="/create-post" method="POST">
      <label>
        Title:
        <input type="text" name="title" required />
      </label>
      <label>
        Content:
        <textarea name="content" required />
      </label>
      <SubmitButton />
    </form>
  );
}

Enter fullscreen mode Exit fullscreen mode

Benefits:

  • Simplifies form submission state management
  • Integrates automatically with React form actions
  • Keeps your code clean without extra local state

Tip/Mistake 3: Tailwind CSS Classes You Didn’t Know (sr-only and Others)

Many developers overlook useful Tailwind CSS classes that improve accessibility and UI ease.

Example: Using sr-only to Hide Content from the UI but Keep It for Screen Readers

export default function AccessibleInfo() {
  return (
    <div className="relative p-4">
      <div className="sr-only">
        This button opens a modal with detailed information.
      </div>
      <button
        onClick={() => alert('Modal opened')}
        className="bg-blue-500 text-white px-4 py-2 rounded-lg hover:bg-blue-600 transition"
      >
        Open Modal
      </button>
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

If you want the element to be visible on larger screens, use not-sr-only:

export default function AccessibleInfo() {
  return (
    <div className="relative p-4">
      <div className="sr-only sm:not-sr-only">
        This button opens a modal with detailed information.
      </div>
      <button
        onClick={() => alert('Modal opened')}
        className="bg-blue-500 text-white px-4 py-2 rounded-lg hover:bg-blue-600 transition"
      >
        Open Modal
      </button>
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

Text Selection Control

  • select-none: Prevents text selection.
  • select-text: Allows text selection.
  • select-all: Selects all text on click.
  • select-auto: Uses the browser's default behavior.
<div class="select-none">This text cannot be selected.</div>
<div class="select-text">This text can be selected.</div>
<div class="select-all">Click to select all text.</div>
<div class="select-auto">Default text selection behavior.</div>

Enter fullscreen mode Exit fullscreen mode

Scrolling Settings

  • scroll-auto: Normal scrolling.
  • scroll-smooth: Smooth scrolling.
<div class="scroll-smooth h-40 overflow-y-scroll">
  <!-- Content here -->
</div>

Enter fullscreen mode Exit fullscreen mode

Hiding the Default File Input

<label class="bg-blue-500 text-white px-4 py-2 rounded cursor-pointer">
  Choose a file
  <input type="file" class="file:hidden" />
</label>

Enter fullscreen mode Exit fullscreen mode

Tip/Mistake 4: Using Component Libraries vs. Native Code

Many developers start projects by using ready-made UI components from popular libraries. This is convenient because these libraries offer many features "out of the box." However, as your app grows, importing an entire library like react-select can add about 95 kB to your final bundle, which slows down your app.

Rule: Use ready-made libraries for a quick start, but switch to native solutions when your project scales.

Example Using react-select:

import React from 'react';
import Select from 'react-select';

const options = [
  { value: 'chocolate', label: 'Chocolate' },
  { value: 'strawberry', label: 'Strawberry' },
  { value: 'vanilla', label: 'Vanilla' },
];

const App = () => (
  <Select options={options} />
);

export default App;

Enter fullscreen mode Exit fullscreen mode

Example Using Native <select>:

import React, { useState } from 'react';
import './App.css'; // Animation styles

const options = [
  { value: 'chocolate', label: 'Chocolate' },
  { value: 'strawberry', label: 'Strawberry' },
  { value: 'vanilla', label: 'Vanilla' },
];

const App = () => {
  const [selectedValue, setSelectedValue] = useState('');

  return (
    <div>
      <select
        className="custom-select"
        value={selectedValue}
        onChange={(e) => setSelectedValue(e.target.value)}
      >
        <option disabled value="">
          Choose an option
        </option>
        {options.map((option) => (
          <option key={option.value} value={option.value}>
            {option.label}
          </option>
        ))}
      </select>
    </div>
  );
};

export default App;

Enter fullscreen mode Exit fullscreen mode

Tip/Mistake 5: The Depcheck Tool

Depcheck is a tool that checks your code to find dependencies listed in your package.json that are not actually used in your project. This helps reduce your app’s size by removing unnecessary packages.

How to Use Depcheck:

  1. Install depcheck:

    yarn global add depcheck
    
    
  2. Imagine you have this package.json:

    {
      "dependencies": {
        "react": "^18.2.0",
        "lodash": "^4.17.21",
        "moment": "^2.29.4"
      }
    }
    
    
  3. Run depcheck:

    yarn depcheck
    
    

Expected Output (if lodash and moment are unused):

Unused dependencies:
* lodash
* moment

Unused devDependencies:
* none

Missing dependencies:
* none

Enter fullscreen mode Exit fullscreen mode

Full video (please like and subscribe) - https://youtu.be/KCh6ztZBJoY

Tip/Mistake 6: Optimizing Enums

TypeScript’s enum is useful for grouping values, but it has drawbacks:

  • It increases the bundle size due to extra reverse mapping code.
  • It can cause issues with tree shaking.
  • It may introduce bugs with reverse mapping.

Solution: Replace enum with an object using the as const modifier.

Example with enum:

export enum EnumSTATUSES {
  SUCCESS = 'SUCCESS',
  ERROR = 'ERROR',
  PENDING = 'PENDING'
}

Enter fullscreen mode Exit fullscreen mode

Example with as const:

export const EnumSTATUSES = {
  SUCCESS: 'SUCCESS',
  ERROR: 'ERROR',
  PENDING: 'PENDING'
} as const;

type EnumStatusesType = (typeof EnumSTATUSES)[keyof typeof EnumSTATUSES];

Enter fullscreen mode Exit fullscreen mode

Using as const makes the object immutable and lets TypeScript infer exact types (e.g., 'SUCCESS' | 'ERROR' | 'PENDING').


Tip/Mistake 7: Choosing Between useEffect and useLayoutEffect

Using the wrong hook can cause visual glitches and performance issues.

The Difference:

  • useEffect: Runs after the component renders; changes are visible.
  • useLayoutEffect: Runs synchronously after rendering but before the browser updates the screen.

Example with useEffect:

import React, { useState, useEffect, useRef } from 'react';

function ResizableBox() {
  const [width, setWidth] = useState(200);
  const boxRef = useRef(null);

  useEffect(() => {
    if (boxRef.current) {
      const newWidth = boxRef.current.offsetWidth;
      setWidth(newWidth);
    }
  }, []);

  return (
    <div>
      <div
        ref={boxRef}
        style={{ width: '100%', border: '1px solid black', height: '50px' }}
      >
        I change my width!
      </div>
      <p>Current width: {width}px</p>
    </div>
  );
}

export default ResizableBox;

Enter fullscreen mode Exit fullscreen mode

Example with useLayoutEffect:

import React, { useState, useLayoutEffect, useRef } from 'react';

function ResizableBox() {
  const [width, setWidth] = useState(200);
  const boxRef = useRef(null);

  useLayoutEffect(() => {
    if (boxRef.current) {
      const newWidth = boxRef.current.offsetWidth;
      setWidth(newWidth);
    }
  }, []);

  return (
    <div>
      <div
        ref={boxRef}
        style={{ width: '100%', border: '1px solid black', height: '50px' }}
      >
        I change my width!
      </div>
      <p>Current width: {width}px</p>
    </div>
  );
}

export default ResizableBox;

Enter fullscreen mode Exit fullscreen mode

Using useLayoutEffect ensures changes occur before the user sees the update, avoiding visual glitches.


Tip/Mistake 8: The Knip Tool

Knip is an advanced static analysis tool that checks not only your dependencies but also unused CSS classes, functions, variables, and files.

How to Use Knip:

  1. Install Knip:

    yarn add knip
    
    
  2. Example CSS file:

    /* App.css */
    .used-class {
      color: blue;
    }
    
    .unused-class {
      font-size: 20px; /* This class is not used */
    }
    
    
  3. Example JavaScript file:

    // src/App.js
    import React from 'react';
    import _ from 'lodash';
    
    // Unused function
    const unusedFunction = () => {
      console.log('This function is never called');
    };
    
    const App = () => {
      return (
        <div className="used-class">
          {_.join(['Hello', 'World'], ' ')}
        </div>
      );
    };
    
    export default App;
    
    
  4. Example of an unused file:

    // src/oldFile.js
    export const oldVariable = 'This variable is never used';
    
    
  5. Run Knip:

    yarn knip
    
    

Knip will analyze your project and list unused CSS classes, exports, and files. Use it regularly to keep your code clean.


Tip/Mistake 9: Missing key When Rendering Lists

Forgetting the key attribute when rendering lists can lead to performance issues and unpredictable component behavior.

Why key is Important:

  • Stability: If the order of items changes, using indexes can cause loss of state.
  • Performance: React updates only the changed elements when unique keys are provided.

Bad Example (No key):

const items = ['Apple', 'Banana', 'Cherry'];

function BadList() {
  return (
    <ul>
      {items.map((item) => (
        <li>{item}</li> // Missing key
      ))}
    </ul>
  );
}

Enter fullscreen mode Exit fullscreen mode

Good Example (Using Unique key):

const items = [
  { id: 1, name: 'Apple' },
  { id: 2, name: 'Banana' },
  { id: 3, name: 'Cherry' },
];

function BetterList() {
  return (
    <ul>
      {items.map((item) => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
}

Enter fullscreen mode Exit fullscreen mode

Using unique IDs instead of indexes ensures stable and efficient list rendering.


Tip/Mistake 10: Use a Seeder on the Back-End

Using a Seeder is an efficient way to populate your database with initial or test data. This speeds up development and testing.

Example Seeder for an Online Store:

const products = [
  {
    name: 'Laptop',
    description: 'A powerful laptop',
    price: 899.99,
    stock: 50
  },
  {
    name: 'Smartphone',
    description: 'A top-tier smartphone',
    price: 799.99,
    stock: 30
  },
  {
    name: 'Headphones',
    description: 'Premium wireless headphones',
    price: 349.99,
    stock: 20
  }
];

async function seedDatabase() {
  try {
    // Make sure to use the correct model and method for creating entries
    await Product.bulkCreate(products);
    console.log('Database seeded successfully');
  } catch (error) {
    console.error('Error seeding the database:', error);
  }
}

seedDatabase();

Enter fullscreen mode Exit fullscreen mode

Explanation:

  • Products Array: Contains objects with product details (name, description, price, stock).
  • seedDatabase Function: Populates the database using the bulkCreate method. On success, it logs a message; on error, it logs the error.

Full video (please like and subscribe) - https://youtu.be/KCh6ztZBJoY

Top comments (0)