Overview
SAAC Frontend uses React 19 with TypeScript for building type-safe, modern components. The project leverages React’s latest features including hooks, Fast Refresh, and the new JSX transform.
Main App Component
The default App.tsx demonstrates core React patterns:
import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
function App () {
const [ count , setCount ] = useState ( 0 )
return (
<>
< div >
< a href = "https://vite.dev" target = "_blank" >
< img src = { viteLogo } className = "logo" alt = "Vite logo" />
</ a >
< a href = "https://react.dev" target = "_blank" >
< img src = { reactLogo } className = "logo react" alt = "React logo" />
</ a >
</ div >
< h1 > Vite + React </ h1 >
< div className = "card" >
< button onClick = { () => setCount (( count ) => count + 1 ) } >
count is { count }
</ button >
< p >
Edit < code > src/App.tsx </ code > and save to test HMR
</ p >
</ div >
< p className = "read-the-docs" >
Click on the Vite and React logos to learn more
</ p >
</>
)
}
export default App
Key Features
State Management Using useState hook for reactive state
Asset Imports Import images directly with proper typing
CSS Modules Component-scoped styles via imports
Event Handlers Type-safe event handling with TypeScript
React 19 Features
Hooks
TypeScript Integration
New JSX Transform
React 19 includes all modern hooks out of the box: import { useState , useEffect , useRef , useMemo , useCallback } from 'react'
function ExampleComponent () {
const [ state , setState ] = useState ( initialValue )
const ref = useRef ( null )
useEffect (() => {
// Side effects
return () => {
// Cleanup
}
}, [ dependencies ])
const memoizedValue = useMemo (() => computeExpensiveValue ( a , b ), [ a , b ])
const memoizedCallback = useCallback (() => doSomething ( a , b ), [ a , b ])
return < div ref = { ref } > Content </ div >
}
Full type inference with React 19 and TypeScript 5.8: // State with type inference
const [ count , setCount ] = useState ( 0 ) // number
const [ name , setName ] = useState ( "" ) // string
// Explicit typing when needed
interface User {
id : number
name : string
}
const [ user , setUser ] = useState < User | null >( null )
// Event handlers are fully typed
const handleClick = ( e : React . MouseEvent < HTMLButtonElement >) => {
e . preventDefault ()
setCount ( count + 1 )
}
The project uses the automatic JSX runtime (no need to import React): // ❌ Old way - NOT needed anymore
import React from 'react'
// ✅ New way - just import what you use
import { useState } from 'react'
function Component () {
return < div > JSX works automatically! </ div >
}
This is configured in tsconfig.app.json: {
"compilerOptions" : {
"jsx" : "react-jsx"
}
}
Component Patterns
Functional Components with TypeScript
Basic Function Component
function Greeting () {
return < h1 > Hello, World! </ h1 >
}
export default Greeting
Component with Props
interface ButtonProps {
label : string
onClick : () => void
disabled ?: boolean
}
function Button ({ label , onClick , disabled = false } : ButtonProps ) {
return (
< button onClick = { onClick } disabled = { disabled } >
{ label }
</ button >
)
}
export default Button
Component with State and Effects
import { useState , useEffect } from 'react'
interface DataComponentProps {
apiUrl : string
}
function DataComponent ({ apiUrl } : DataComponentProps ) {
const [ data , setData ] = useState < string | null >( null )
const [ loading , setLoading ] = useState ( true )
useEffect (() => {
fetch ( apiUrl )
. then ( res => res . json ())
. then ( data => {
setData ( data )
setLoading ( false )
})
}, [ apiUrl ])
if ( loading ) return < div > Loading... </ div >
return < div > { data } </ div >
}
export default DataComponent
Component Organization
Recommended Structure
src/
├── components/
│ ├── common/ # Reusable UI components
│ │ ├── Button/
│ │ │ ├── Button.tsx
│ │ │ ├── Button.css
│ │ │ └── index.ts
│ │ └── Input/
│ │ ├── Input.tsx
│ │ └── index.ts
│ ├── features/ # Feature-specific components
│ │ ├── Auth/
│ │ └── Dashboard/
│ └── layout/ # Layout components
│ ├── Header.tsx
│ ├── Footer.tsx
│ └── Sidebar.tsx
├── App.tsx
└── main.tsx
Index Files for Clean Imports
src/components/Button/index.ts
export { default } from './Button'
export type { ButtonProps } from './Button'
import Button from './components/Button'
import Button from './components/Button/Button'
TypeScript Best Practices
Always define explicit interfaces for component props: // ✅ Good
interface CardProps {
title : string
description ?: string
children : React . ReactNode
}
function Card ({ title , description , children } : CardProps ) {
return (
< div >
< h2 > { title } </ h2 >
{ description && < p > { description } </ p > }
{ children }
</ div >
)
}
// ❌ Avoid
function Card ( props : any ) {
return < div > { props . title } </ div >
}
Prefer explicit typing over React.FC: // ✅ Recommended
interface Props {
name : string
}
function Component ({ name } : Props ) {
return < div > { name } </ div >
}
// ⚠️ Less preferred (but valid)
const Component : React . FC < Props > = ({ name }) => {
return < div > { name } </ div >
}
Use proper React event types: function Form () {
const handleSubmit = ( e : React . FormEvent < HTMLFormElement >) => {
e . preventDefault ()
// Handle form submission
}
const handleChange = ( e : React . ChangeEvent < HTMLInputElement >) => {
console . log ( e . target . value )
}
const handleClick = ( e : React . MouseEvent < HTMLButtonElement >) => {
console . log ( 'Clicked' )
}
return (
< form onSubmit = { handleSubmit } >
< input onChange = { handleChange } />
< button onClick = { handleClick } > Submit </ button >
</ form >
)
}
Creating New Components
Create component file
touch src/components/MyComponent.tsx
Define props interface and component
src/components/MyComponent.tsx
interface MyComponentProps {
title : string
onAction ?: () => void
}
function MyComponent ({ title , onAction } : MyComponentProps ) {
return (
< div >
< h2 > { title } </ h2 >
{ onAction && < button onClick = { onAction } > Action </ button > }
</ div >
)
}
export default MyComponent
Add styles (optional)
import './MyComponent.css'
Import and use in App
import MyComponent from './components/MyComponent'
function App () {
return (
< MyComponent
title = "Hello"
onAction = { () => console . log ( 'Action!' ) }
/>
)
}
The TypeScript configuration has strict: true enabled, which helps catch type errors early and ensures type safety throughout your components.
Asset Imports
Import assets directly in components with full type support:
// Images
import logo from './assets/logo.png'
import icon from './assets/icon.svg'
// Public assets (referenced by path)
const publicAsset = '/vite.svg'
function Component () {
return (
< div >
< img src = { logo } alt = "Logo" /> { /* From src/assets/ */ }
< img src = { icon } alt = "Icon" /> { /* From src/assets/ */ }
< img src = { publicAsset } alt = "Public" /> { /* From public/ */ }
</ div >
)
}
The vite-env.d.ts file provides type definitions for asset imports:
/// < reference types = "vite/client" />