Appearance
React Template
The React template provides a frontend development environment using React, TypeScript, and Vite. It includes pre-configured platform integration utilities for data fetching, authentication handling, and asynchronous state management.
Project Structure
src/
├── main.tsx # Application entry point
├── App.tsx # Root component with routing
├── index.scss # Global styles
├── lib/ # Platform utilities
│ ├── future/ # Future utilities for async state
│ ├── fetch/ # Data fetching with auth handling
│ └── ... # Other platform utilities
└── components/ # Reusable UI componentsDependencies
The template uses the following key packages (defined in package.json):
- React - UI library for building component-based interfaces
- TypeScript - Type-safe JavaScript superset
- Vite - Fast build tool and development server
- React Router - Client-side routing
- React Bootstrap - Pre-built UI components
- Lucide React - Icon library
- Sass - CSS preprocessor for styling
Setup Instructions
1. Install Dependencies
bash
npm install2. Configure Environment Variables
Create a .env file in the project root with the required platform configuration. See Creating Your First Application for details on obtaining these values.
Development Workflow
Running the Development Server
bash
npm startThis starts the Vite development server on http://localhost:5173 (or next available port) with:
- Hot Module Replacement (HMR) - Instant updates without full page reload
- Fast refresh - Preserves component state during updates
- API proxying - Automatically proxies backend and gateway API calls
Building for Production
bash
npm run buildThis creates an optimized production bundle in the dist/ directory with:
- Minified JavaScript and CSS
- Tree-shaking to remove unused code
- Source maps for debugging
- Optimized asset loading
Preview Production Build
bash
npm run previewServes the production build locally for testing before deployment.
Vite Configuration
The template uses Vite for fast development and optimized builds. Key configuration features in vite.config.ts:
API Proxying
Vite automatically proxies API requests during development:
ts
proxy: {
"/reload": backend,
"^/api/(?!gw/)": {
target: backend,
headers: {
Authorization: `Bearer ${process.env.APP_BACKEND_REQUEST_TOKEN}`,
},
},
"/api/gw/": {
target: process.env.APP_PLATFORM_URL,
changeOrigin: true,
headers: {
Authorization: `Bearer ${process.env.APP_FRONTEND_TOKEN}`,
},
},
},Benefits:
- No CORS issues during development
- Automatic authentication header injection
- Seamless backend integration
Plugins
- @vitejs/plugin-react - Enables React Fast Refresh
- vite-tsconfig-paths - Resolves TypeScript path aliases (e.g.,
@/lib)
SCSS Support
The template includes Sass preprocessing for advanced styling capabilities.
Platform Integration
The template includes utilities for interacting with backend APIs and the platform gateway. These utilities handle authentication, loading states, and error handling automatically.
Data Fetching
This section describes the available options for fetching data in the React frontend template. The platform provides two main approaches: the useFetch hook for manual control and the WithFetch component for automatic state management.
useFetch Hook
The useFetch hook is a React hook that fetches data from a URL and automatically handles authentication redirects. It returns a Future object that represents the current state of the fetch operation. You can find more information about futures further down on this page.
Usage
tsx
const future = useFetch<WeatherData>(`/api/weather/${location}`);
return (
<WithFuture future={future}>
{(weather) => <WeatherCard data={weather} />}
</WithFuture>
);Parameters
- url (string): The URL to fetch data from
- options (RequestInit, optional): Optional fetch configuration options
- deps (DependencyList, optional): Additional dependencies that trigger re-fetching
Return Value
The hook returns a Future<T> object with the following possible states:
- loading: Data is currently being fetched
- error: An error occurred
- success: Data was successfully fetched (available via
future.data)
How It Works
- Executes an HTTP request to the specified URL
- On a 403 status with Location header, automatically redirects to the location
- After successful authentication, the user is returned to the application
- Automatically parses the response as JSON or text based on the Content-Type header
WithFetch Component
The WithFetch component simplifies data fetching by automatically handling loading and error states by replacing child components with a spinner until the data is loaded.
Usage
tsx
return (
<WithFetch<WeatherData> url={`/api/weather/${location}`}>
{(data) => <WeatherCard data={data} />}
</WithFetch>
);Props
- url (string): The URL to fetch data from
- options (RequestInit, optional): Optional fetch configuration options
- children (function): Render function that receives the fetched data
Behavior
- Automatically displays a spinner while loading
- Automatically displays an error message on failure
- Calls the children function with the data once available
Authentication
WithFetch aswell as useFetch automatically handle authentication redirects:
- On a 403 response with Location header, the user is redirected to the provided location
- The user is redirected for authentication
- After successful authentication, the original request is automatically retried
This works for both backend APIs (/api/...) and Platform Gateway calls (/api/gw/...).
Reloading/Refreshing data
By default, data is fetched when the page is loaded and whenever the URL changes. If data needs to be reloaded, for example after an API call to modify some data, the easiest way is to use the global reload:
tsx
return (
<WithFetch<string> url={`/api/current-time`}>
{(data) => (
<>
Now: {data}
<Button onClick={() => globalReload()}>Reload</Button>
</>
)}
</WithFetch>
);Calling the globalReload() function will cause all data loaded unsing useFetch() and <WithFetch/> to be reloaded. If more fine grained reloading is required, useReload() can be used together with the deps option:
tsx
const reload = useReload();
return (
<WithFetch<string> url={`/api/current-time`} options={{ deps: [reload] }}>
{(data) => (
<>
Now: {data}
<Button onClick={() => reload.trigger()}>Reload</Button>
</>
)}
</WithFetch>
);Of course, the deps option can be used with any other object. It is internally passed to the deps array of a useEffect.
The last option for data refreshing is polling:
tsx
return (
<WithFetch<string> url={`/api/current-time`} options={{ poll: 1000 }}>
{(data) => <>Now: {data}</>}
</WithFetch>
);This polls the data every x milliseconds.
Future Utilities
The Future Utilities provides a comprehensive set of utilities for handling asynchronous operations in React applications. It's built around the Future type, which represents an async operation that can be in one of three states: loading, error, or complete.
Concept
The Future pattern is a type-safe way to handle async operations. Instead of managing loading states, error states, and data separately, a Future encapsulates all three states in a discriminated union:
ts
export type Future<T> =
| { state: "loading" }
| { state: "complete"; data: T }
| { state: "error"; error: any };Utilities
mapFuture
Transforms the data of a Future using a synchronous function.
tsx
const simplifiedWeather = mapFuture(weatherFuture, (data) => ({
location: data.location.name,
temperature: data.current.temp_c,
condition: data.current.condition.text,
}));Parameters:
future: The Future to transformfn: Function to transform the data if the Future is complete
Returns: A new Future with the transformed data
Use Case: Transform data if the future is in its completed state without triggering re-renders or side effects.
Hooks
usePromise
Wraps a promise factory and returns a Future with loading, error, and success states.
tsx
const promiseFuture = usePromise(async () => {
const response = await fetch(`/api/weather/${location}`);
return response.json() as Promise<WeatherData>;
}, [location]);Parameters:
factory: Function that returns a Promise to executedeps: Dependency array that triggers re-execution when changed
Returns: A Future<T> representing the promise state
Use Case: Convert any promise-based async operation into a Future.
useFutureEffect
Runs an effect when a Future completes successfully.
tsx
const weatherFuture = useFetch<WeatherData>(`/api/weather/${location}`);
useFutureEffect(
weatherFuture,
(data) => {
setEffectLog((prev) => [
...prev,
`Weather loaded for ${data.location.name}`,
]);
},
[],
);Parameters:
input: The Future to watcheffect: Effect function to run when the Future completes successfullydeps: Additional dependencies for the effect
Use Case: Trigger side effects (logging, analytics, notifications) when async operations complete.
useFutureEffects
Runs an effect when all Futures complete successfully.
tsx
const londonWeather = useFetch<WeatherData>("/api/weather/London");
const parisWeather = useFetch<WeatherData>("/api/weather/Paris");
useFutureEffects(
{ london: londonWeather, paris: parisWeather },
({ london, paris }) => {
setEffectLog((prev) => [
...prev,
`Both cities loaded: ${london.location.name} & ${paris.location.name}`,
]);
},
[],
);Parameters:
inputs: Object containing multiple Futures to watcheffect: Effect function to run when all Futures complete successfullydeps: Additional dependencies for the effect
Use Case: Coordinate side effects that depend on multiple async operations completing.
useFutureMemo
Memoizes a synchronous transformation of a Future.
tsx
const temperatureFuture = useFutureMemo(
weatherFuture,
(data) => ({
celsius: data.current.temp_c,
fahrenheit: data.current.temp_f,
location: data.location.name,
}),
[],
);Parameters:
input: The Future to transformfn: Function to transform the data if the Future is successfuldeps: Additional dependencies that trigger re-computation
Returns: A memoized Future with the transformed data
Use Case: Derive computed values from futures without unnecessary re-computations.
useFutureMemos
Memoizes a transformation of multiple Futures.
tsx
const combinedWeather = useFutureMemos(
{ london: londonWeather, paris: parisWeather },
({ london, paris }) => ({
avgTemp: (london.current.temp_c + paris.current.temp_c) / 2,
cities: [london.location.name, paris.location.name],
}),
[],
);Parameters:
inputs: Object containing multiple Futures to combinefn: Function to transform the combined data when all Futures are successfuldeps: Additional dependencies that trigger re-computation
Returns: A memoized Future with the transformed combined data
Use Case: Combine and transform data from multiple async sources efficiently.
useFutureMap
Maps a Future through an asynchronous transformation function.
tsx
const enrichedWeather = useFutureMap(
weatherFuture,
async (data) => {
// Simulate an async transformation
await new Promise((resolve) => setTimeout(resolve, 100));
return {
...data,
enriched: true,
timestamp: new Date().toISOString(),
};
},
[],
);Parameters:
input: The Future to transformfn: Async function to transform the data if the Future is successfuldeps: Additional dependencies that trigger re-execution
Returns: A Future representing the async transformation
Use Case: Chain async operations, such as fetching data and then processing it with another async call.
Components
WithFutures
Component that waits for multiple Futures to complete and renders children with the combined data.
tsx
const weather1 = useFetch<WeatherData>("/api/weather/London");
const weather2 = useFetch<WeatherData>("/api/weather/Paris");tsx
}
<WithFutures futures={{ weather1, weather2 }}>
{({ weather1, weather2 }) => (
<Stack gap={3}>
<WeatherCard data={weather1} />
<WeatherCard data={weather2} />
</Stack>
)}
</WithFutures>
{Props:
futures: Object containing multiple Futures to wait forchildren: Render function that receives the combined data from all Futures
Behavior:
- Displays a spinner while any Future is loading
- Displays an error alert if any Future fails
- Calls the children function with combined data once all Futures are complete
Use Case: Declaratively render UI that depends on multiple async operations.
When to Use What?
Use usePromise when:
- You need to convert existing promise code to Futures
- You want full control over the promise execution
Use useFutureEffect when:
- You need to trigger side effects on completion
- You need to coordinate with external systems
Use useFutureMemo when:
- You need to derive computed values from async data
- You want to avoid unnecessary re-computations
- The transformation is synchronous
Use useFutureMap when:
- You need to chain async operations
- You want to process data asynchronously
Use WithFutures when:
- You need to wait for multiple async operations
- You want declarative rendering based on async state
Integration with Data Fetching
The Future Utilities integrate seamlessly with the data fetching utilities:
tsx
const integrationWeatherFuture = useFetch<WeatherData>("/api/weather/London");
const integrationTempFuture = useFutureMemo(
integrationWeatherFuture,
(data) => data.current.temp_c,
[],
);Next Steps
- Review Frontend Data Fetching for platform API integration patterns
- Explore Framework Specific Frontend Conventions for advanced React patterns
- Check Demo Applications & Examples for complete working examples