Starting a project

Start a project, know what each file is for, and get a component onto the page.

02of 20
≈ 9Min read
7Parts

Creating one

create-react-app is no longer maintained. Vite starts instantly, rebuilds in milliseconds, and its production build is a normal static folder.

Vite is the default answer now
npm create vite@latest my-app -- --template react
cd my-app
npm install
npm run dev        // http://localhost:5173

npm run build      // → dist/
npm run preview    // serve the built version locally

The files

what matters and what does not
index.html          ← the real entry point; Vite reads this
src/
  main.jsx          ← finds #root and renders <App />
  App.jsx           ← your top component
  components/       ← the rest
  index.css
public/             ← copied verbatim; reference as /file.png
vite.config.js
package.json
index.html is the entry, not a template

Unlike older tooling, Vite treats index.html as source. The <script type="module" src="/src/main.jsx"> in it is what starts everything.

Mounting

  • createRoot is the React 18 API. ReactDOM.render is the old one and is gone.
  • One root per application. You can have several on a page — useful when adding React to an existing site a piece at a time.
  • Importing CSS from a component is a bundler feature, not a React one. It works because Vite handles it.
main.jsx, in full
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.jsx";
import "./index.css";

createRoot(document.getElementById("root")).render(
  <StrictMode>
    <App />
  </StrictMode>
);

StrictMode

In development, StrictMode deliberately runs your components twice and mounts, unmounts and remounts every effect once. It is not a bug and it does not happen in production.

It exists to surface two mistakes: a component that is not pure (it changes something outside itself during render) and an effect with no cleanup. If double-rendering breaks your component, the component is wrong.

The usual symptom

A request fires twice in development, or a counter increments by two. Both mean the work is happening during render or in an effect without cleanup — fix the cause, do not remove StrictMode.

A component per file

  • A component name starts with a capital letter. JSX treats a lower-case name as an HTML tag.
  • One component per file, named after the file. Small helper components in the same file are fine.
  • A default export per file is the convention here, even though named exports are generally better — the tooling and every tutorial assume it.
Card.jsx
export default function Card({ door }) {
  return (
    <article className="card">
      <h3>{door.name}</h3>
      <p>{door.days} days</p>
    </article>
  );
}
App.jsx
import Card from "./components/Card.jsx";

export default function App() {
  return (
    <main>
      <h1>Doors</h1>
      <Card door={{ name: "Painted", days: 5 }} />
    </main>
  );
}

The dev server

  • Changes appear without a reload — hot module replacement keeps component state where it can.
  • An error appears as an overlay with the file and line, not only in the console.
  • The dev server is not the production build. Test npm run build && npm run preview before shipping.

Adding React to an existing page

This is often the right way in: keep the pages you have, and use React only for the parts that are genuinely interactive.

you do not need a whole SPA
// one widget on a server-rendered page
const el = document.getElementById("configurator");
if (el) createRoot(el).render(<Configurator />);

Practice