### Route File Example in JavaScript
Source: https://feature-sliced.github.io/documentation/docs/guides/migration/from-custom
Example of a route file that exports a page component. This demonstrates how a route can be a thin wrapper around a page, simplifying routing logic.
```javascript
export { ProductPage as default } from "@/pages/product"
```
--------------------------------
### Page Index File Example in JavaScript
Source: https://feature-sliced.github.io/documentation/docs/guides/migration/from-custom
Example of an index file for a page, exporting the main page component. This pattern centralizes the page's export, making it easier to import and use elsewhere.
```javascript
export { ProductPage } from "./ProductPage.jsx"
```
--------------------------------
### Index Route Setup (TypeScript)
Source: https://feature-sliced.github.io/documentation/docs/get-started/tutorial
Configures the root index route ('/'). It imports the FeedPage component and its loader from the 'pages/feed' module. It also defines the page metadata, setting the title to 'Conduit'. Dependencies include '@remix-run/node' and 'pages/feed'.
```typescript
import type { MetaFunction } from "@remix-run/node";
import { FeedPage } from "pages/feed";
export { loader } from "pages/feed";
export const meta: MetaFunction = () => {
return [{ title: "Conduit" }];
};
export default FeedPage;
```
--------------------------------
### Page Component Example in JSX
Source: https://feature-sliced.github.io/documentation/docs/guides/migration/from-custom
A basic example of a page component written in JSX. This functional component serves as a placeholder and can be expanded with specific page logic and UI elements.
```jsx
export function ProductPage(props) {
return
;
}
```
--------------------------------
### Axios Client Setup for API Requests
Source: https://feature-sliced.github.io/documentation/docs/guides/examples/api-requests
Centralizes HTTP request setup using Axios, configuring the base URL, timeout, and default headers. This promotes consistent API communication across the application.
```typescript
import axios from 'axios';
export const client = axios.create({
baseURL: 'https://your-api-domain.com/api/',
timeout: 5000,
headers: { 'X-Custom-Header': 'my-custom-value' }
});
```
--------------------------------
### Simple React Page Layout Component
Source: https://feature-sliced.github.io/documentation/docs/guides/examples/page-layout
A basic React layout component demonstrating navigation, theme switching, sidebars, and content rendering using React Router's Outlet. It depends on react-router-dom for routing and a custom useThemeSwitcher hook.
```tsx
import { Link, Outlet } from "react-router-dom";
import { useThemeSwitcher } from "./useThemeSwitcher";
export function Layout({ siblingPages, headings }) {
const [theme, toggleTheme] = useThemeSwitcher();
return (
{/* This is where the main content goes */}
);
}
```
--------------------------------
### Basic Query Factory Example
Source: https://feature-sliced.github.io/documentation/docs/guides/tech/with-react-query
A simple example of a query factory where keys are functions returning query keys. This demonstrates the fundamental structure for organizing query definitions.
```javascript
const keyFactory = {
all: () => ["entity"],
lists: () => [...postQueries.all(), "list"],
};
```
--------------------------------
### Integrate Home Page into SvelteKit Route
Source: https://feature-sliced.github.io/documentation/docs/guides/tech/with-sveltekit
This code example shows how to render a page component within a SvelteKit route. It imports the 'HomePage' component from the 'pages/home' layer using the configured alias and renders it in the 'src/app/routes/+page.svelte' file.
```html
```
--------------------------------
### Article Read Page Exports (TypeScript)
Source: https://feature-sliced.github.io/documentation/docs/get-started/tutorial
Exports for the article-read page, including the main page component, loader, and action functions. These are intended to be imported and used by the Remix routing setup.
```typescript
export { ArticleReadPage } from "./ui/ArticleReadPage";
export { loader } from "./api/loader";
export { action } from "./api/action";
```
--------------------------------
### Export API Client Methods for Application Use
Source: https://feature-sliced.github.io/documentation/docs/get-started/tutorial
This TypeScript file exports the HTTP methods (GET, POST, PUT, DELETE) from the API client module. This allows other parts of the application to easily import and use the API client.
```typescript
export { GET, POST, PUT, DELETE } from "./client";
```
--------------------------------
### Feed API Loader (TypeScript)
Source: https://feature-sliced.github.io/documentation/docs/get-started/tutorial
Implements a Remix loader function to fetch articles from the backend API. It uses the shared API client to make a GET request to '/articles'. Error handling is included, throwing an error if the API request fails. Dependencies include '@remix-run/node' and 'shared/api'.
```typescript
import { json } from "@remix-run/node";
import { GET } from "shared/api";
export const loader = async () => {
const { data: articles, error, response } = await GET("/articles");
if (error !== undefined) {
throw json(error, { status: response.status });
}
return json({ articles });
};
```
--------------------------------
### Fetch API Client Setup for POST Requests
Source: https://feature-sliced.github.io/documentation/docs/guides/examples/api-requests
Implements a basic POST request function using the native Fetch API. It handles JSON serialization, sets common headers like 'Content-Type', and merges provided options. Supports other methods like PUT and DELETE with further implementation.
```typescript
export const client = {
async post(endpoint: string, body: any, options?: RequestInit) {
const response = await fetch(`https://your-api-domain.com/api${endpoint}`, {
method: 'POST',
body: JSON.stringify(body),
...options,
headers: {
'Content-Type': 'application/json',
'X-Custom-Header': 'my-custom-value',
...options?.headers,
},
});
return response.json();
}
// ... other methods like put, delete, etc.
};
```
--------------------------------
### Client-side Registration Validation Schema (Zod)
Source: https://feature-sliced.github.io/documentation/docs/guides/examples/auth
Defines a Zod schema for validating registration data, including email format, password length, and password confirmation matching. This schema is used to provide immediate feedback to users on the client-side. It expects an object with 'email', 'password', and 'confirmPassword' properties.
```typescript
import { z } from "zod";
export const registrationData = z.object({
email: z.string().email(),
password: z.string().min(6),
confirmPassword: z.string(),
}).refine((data) => data.password === data.confirmPassword, {
message: "Passwords do not match",
path: ["confirmPassword"],
});
```
--------------------------------
### Create Home Page Component and Route
Source: https://feature-sliced.github.io/documentation/docs/guides/tech/with-sveltekit
This snippet demonstrates creating a page slice for a home page using the FSD CLI, defining its public API, and setting up the corresponding route within the SvelteKit application. It involves creating a 'home-page.svelte' file in the 'ui' segment and exporting it from 'src/pages/home/index.ts'.
```bash
fsd pages home
```
```typescript
export { default as HomePage } from './ui/home-page.svelte';
```
--------------------------------
### Create Shared UI Directory
Source: https://feature-sliced.github.io/documentation/docs/get-started/tutorial
Command to generate a new directory structure for shared UI components using the fsd CLI.
```bash
npx fsd shared ui
```
--------------------------------
### Generate API Client and Config Segments
Source: https://feature-sliced.github.io/documentation/docs/get-started/tutorial
This command uses the 'fsd' CLI tool to generate the 'api' and 'config' segments within the 'shared' directory. These segments will hold the API client logic and configuration variables, respectively.
```bash
npx fsd shared --segments api config
```
--------------------------------
### Root Layout and Loader (Remix/TypeScript)
Source: https://feature-sliced.github.io/documentation/docs/get-started/tutorial
Configures the root layout of the Remix application. It includes the Header component, wraps the Outlet with the CurrentUser context provider, and defines a loader function to fetch user session data.
```typescript
import { cssBundleHref } from "@remix-run/css-bundle";
import type { LinksFunction, LoaderFunctionArgs } from "@remix-run/node";
import {
Links,
LiveReload,
Meta,
Outlet,
Scripts,
ScrollRestoration,
useLoaderData,
} from "@remix-run/react";
import { Header } from "shared/ui";
import { getUserFromSession, CurrentUser } from "shared/api";
export const links: LinksFunction = () => [
...(cssBundleHref ? [{ rel: "stylesheet", href: cssBundleHref }] : []),
];
export const loader = ({ request }: LoaderFunctionArgs) =>
getUserFromSession(request);
export default function App() {
```
--------------------------------
### Create Typed API Client with openapi-fetch
Source: https://feature-sliced.github.io/documentation/docs/get-started/tutorial
This TypeScript code snippet demonstrates how to create a typed API client using the 'openapi-fetch' package. It imports the necessary function and types, configures the client with the backend base URL, and exports HTTP methods for use.
```typescript
import createClient from "openapi-fetch";
import { backendBaseUrl } from "shared/config";
import type { paths } from "./v1";
export const { GET, POST, PUT, DELETE } = createClient({
baseUrl: backendBaseUrl,
});
```
--------------------------------
### API Client Export (TypeScript)
Source: https://feature-sliced.github.io/documentation/docs/get-started/tutorial
Exports the HTTP methods (GET, POST, PUT, DELETE) from the API client and re-exports the 'Article' type. This provides a centralized point for API interactions and data type definitions. It depends on './client' and './models'.
```typescript
export { GET, POST, PUT, DELETE } from "./client";
export type { Article } from "./models";
```
--------------------------------
### Environment Variable Configuration (.env)
Source: https://feature-sliced.github.io/documentation/docs/get-started/tutorial
Specifies the `SESSION_SECRET` environment variable required for secure session management in the Remix application. This variable should be a long, random string and is crucial for encrypting session cookies. The example shows how to set this variable in a `.env` file.
```plaintext
SESSION_SECRET=dontyoudarecopypastethis
```
--------------------------------
### Create Blank Page Components with FSD
Source: https://feature-sliced.github.io/documentation/docs/get-started/tutorial
This command uses the Feature-Sliced Design (FSD) CLI to generate the initial folder structure and index files for multiple pages within the 'pages' segment. It creates subdirectories for 'ui' and an 'index.ts' file for each specified page.
```bash
npx fsd pages feed sign-in article-read article-edit profile settings --segments ui
```
--------------------------------
### App Router API Route Export (TypeScript)
Source: https://feature-sliced.github.io/documentation/docs/guides/tech/with-nextjs
Exports the GET method for an App Router API route by re-exporting a function from the 'api-routes' segment. This is a common pattern for organizing API route logic.
```typescript
export { getExampleData as GET } from '@/app/api-routes';
```
--------------------------------
### Load Feed Articles and Tags in Remix
Source: https://feature-sliced.github.io/documentation/docs/get-started/tutorial
Loads articles and tags for the feed page. It handles optional 'tag' and 'page' query parameters and checks for a 'source' parameter to differentiate between a user's feed and a general feed. Requires user authentication for the 'my-feed' source.
```TypeScript
import { promiseHash } from "remix-utils/promise";
import { GET, requireUser } from "shared/api";
async function throwAnyErrors(
responsePromise: Promise>,
) {
/* unchanged */
}
/** Amount of articles on one page. */
export const LIMIT = 20;
export const loader = async ({ request }: LoaderFunctionArgs) => {
const url = new URL(request.url);
const selectedTag = url.searchParams.get("tag") ?? undefined;
const page = parseInt(url.searchParams.get("page") ?? "", 10);
if (url.searchParams.get("source") === "my-feed") {
const userSession = await requireUser(request);
return json(
await promiseHash({
articles: throwAnyErrors(
GET("/articles/feed", {
params: {
query: {
limit: LIMIT,
offset: !Number.isNaN(page) ? page * LIMIT : undefined,
},
},
headers: { Authorization: `Token ${userSession.token}` },
}),
),
tags: throwAnyErrors(GET("/tags")),
}),
);
}
return json(
await promiseHash({
articles: throwAnyErrors(
GET("/articles", {
params: {
query: {
tag: selectedTag,
limit: LIMIT,
offset: !Number.isNaN(page) ? page * LIMIT : undefined,
},
},
}),
),
tags: throwAnyErrors(GET("/tags")),
}),
);
};
```
--------------------------------
### Custom App Component for Next.js Pages Router
Source: https://feature-sliced.github.io/documentation/docs/guides/tech/with-nextjs
Provides an example of a custom Next.js App component, demonstrating how to wrap the application with additional elements like a paragraph. This component is intended to be placed in `src/app/custom-app` and then re-exported to `pages/_app.tsx`.
```typescript
import type { AppProps } from 'next/app';
export const MyApp = ({ Component, pageProps }: AppProps) => {
return (
<>
My Custom App component
>
);
};
```
--------------------------------
### Sign-in Page UI Component (React)
Source: https://feature-sliced.github.io/documentation/docs/get-started/tutorial
Renders the sign-in form using Remix's Form component. It displays potential errors returned from the signIn action and includes a link to the registration page.
```jsx
import { Form, Link, useActionData } from "@remix-run/react";
import type { signIn } from "../api/sign-in";
export function SignInPage() {
const signInData = useActionData();
return (
Sign in
Need an account?
{signInData?.error && (
{signInData.error.errors.body.map((error) => (
{error}
))}
)}
);
}
```
--------------------------------
### User Registration API Handler (TypeScript)
Source: https://feature-sliced.github.io/documentation/docs/get-started/tutorial
Handles user registration by processing form data, making a POST request to the /users endpoint, and creating a user session upon successful registration. It returns an error if the API call fails.
```typescript
import { json, type ActionFunctionArgs } from "@remix-run/node";
import { POST, createUserSession } from "shared/api";
export const register = async ({ request }: ActionFunctionArgs) => {
const formData = await request.formData();
const username = formData.get("username")?.toString() ?? "";
const email = formData.get("email")?.toString() ?? "";
const password = formData.get("password")?.toString() ?? "";
const { data, error } = await POST("/users", {
body: { user: { email, password, username } },
});
if (error) {
return json({ error }, { status: 400 });
} else {
return createUserSession({
request: request,
user: data.user,
redirectTo: "/",
});
}
};
```
--------------------------------
### Re-export FSD Page in Next.js Pages Router
Source: https://feature-sliced.github.io/documentation/docs/guides/tech/with-nextjs
This snippet demonstrates re-exporting a page component from the FSD `src/pages` directory for use with the Next.js Pages Router. It targets a page named 'example' in `src/pages/example` and exports it as the default component.
```typescript
export { Example as default } from '@/pages/example';
```
--------------------------------
### Bad Practice: Wildcard Re-exports in Public API
Source: https://feature-sliced.github.io/documentation/docs/reference/public-api
This example illustrates a bad practice of using wildcard re-exports ('export * from') in a public API. This approach can hinder discoverability, make refactoring difficult by exposing internal modules, and is generally discouraged.
```javascript
// ❌ BAD CODE BELOW, DON'T DO THIS
export * from "./ui/Comment"; // 👎 don't try this at home
export * from "./model/comments"; // 💩 this is bad practice
```
--------------------------------
### Sign-in API Handler (TypeScript)
Source: https://feature-sliced.github.io/documentation/docs/get-started/tutorial
Handles user sign-in by processing form data, making a POST request to the /users/login endpoint, and creating a user session upon successful login. It returns an error if the API call fails.
```typescript
import { json, type ActionFunctionArgs } from "@remix-run/node";
import { POST, createUserSession } from "shared/api";
export const signIn = async ({ request }: ActionFunctionArgs) => {
const formData = await request.formData();
const email = formData.get("email")?.toString() ?? "";
const password = formData.get("password")?.toString() ?? "";
const { data, error } = await POST("/users/login", {
body: { user: { email, password } },
});
if (error) {
return json({ error }, { status: 400 });
} else {
return createUserSession({
request: request,
user: data.user,
redirectTo: "/",
});
}
};
```
--------------------------------
### React Component Rendering with Data Loading
Source: https://feature-sliced.github.io/documentation/docs/get-started/tutorial
This snippet demonstrates a React component that uses the `useLoaderData` hook to fetch data and renders an HTML structure. It includes meta tags, stylesheets, and integrates with other components like Header and Outlet. Dependencies include React and Remix.
```jsx
const user = useLoaderData();
return (
);
}
```
--------------------------------
### React Theme Switcher Custom Hook
Source: https://feature-sliced.github.io/documentation/docs/guides/examples/page-layout
A custom React hook for managing and toggling a light/dark theme. It utilizes useState for theme state and useEffect to update the document body's classList based on the current theme. It returns the current theme and a function to toggle it.
```ts
export function useThemeSwitcher() {
const [theme, setTheme] = useState("light");
function toggleTheme() {
setTheme(theme === "light" ? "dark" : "light");
}
useEffect(() => {
document.body.classList.remove("light", "dark");
document.body.classList.add(theme);
}, [theme]);
return [theme, toggleTheme] as const;
}
```
--------------------------------
### Connect Feed Page to Root Route (Remix/TypeScript)
Source: https://feature-sliced.github.io/documentation/docs/get-started/tutorial
This Remix route file (`app/routes/_index.tsx`) connects the application's root route to the FeedPage component. It imports the necessary MetaFunction type and the FeedPage component, sets the page metadata, and exports FeedPage as the default export, which Remix uses to render the page.
```typescript
import type { MetaFunction } from "@remix-run/node";
import { FeedPage } from "pages/feed";
export const meta: MetaFunction = () => {
return [{ title: "Conduit" }];
};
export default FeedPage;
```
--------------------------------
### Public API Exports (TypeScript)
Source: https://feature-sliced.github.io/documentation/docs/get-started/tutorial
Exports core functionalities for public use from the shared API module. This includes HTTP methods (GET, POST, PUT, DELETE) from the client, the Article type definition, and the authentication utilities (createUserSession, getUserFromSession, requireUser). This simplifies integration of these features into other parts of the application.
```typescript
export { GET, POST, PUT, DELETE } from "./client";
export type { Article } from "./models";
export { createUserSession, getUserFromSession, requireUser } from "./auth.server";
```
--------------------------------
### Editor Route Implementation - TypeScript
Source: https://feature-sliced.github.io/documentation/docs/get-started/tutorial
Sets up the Remix routes for the article editor, importing the page component, loader, and action from the feature's API. This configuration supports both creating new articles (editor._index.tsx) and editing existing ones (editor.$slug.tsx) using the same logic.
```typescript
import { ArticleEditPage } from "pages/article-edit";
export { loader, action } from "pages/article-edit";
export default ArticleEditPage;
```
--------------------------------
### Handling Get User Data IPC in Main Process (TypeScript)
Source: https://feature-sliced.github.io/documentation/docs/guides/tech/with-electron
This TypeScript code sets up an IPC listener in the Electron main process to handle the `GET_USER_DATA` channel. It returns mock user data directly as the event's return value.
```typescript
import { ipcMain } from 'electron';
import { CHANNELS } from 'shared/ipc';
export const sendUser = () => {
ipcMain.on(CHANNELS.GET_USER_DATA, ev => {
ev.returnValue = {
name: 'John Doe',
email: 'john.doe@example.com',
};
});
};
```
--------------------------------
### Fetch Filtered Articles with Tag Parameter (TypeScript)
Source: https://feature-sliced.github.io/documentation/docs/get-started/tutorial
This updated Remix loader function incorporates tag filtering. It extracts the 'tag' search parameter from the request URL. The 'GET' request for articles is modified to include this selected tag as a query parameter. If no tag is selected, it defaults to undefined, fetching all articles.
```typescript
import { json, type LoaderFunctionArgs } from "@remix-run/node";
import type { FetchResponse } from "openapi-fetch";
import { promiseHash } from "remix-utils/promise";
import { GET } from "shared/api";
async function throwAnyErrors(
responsePromise: Promise>,
) {
const { data, error, response } = await responsePromise;
if (error !== undefined) {
throw json(error, { status: response.status });
}
return data as NonNullable;
}
export const loader = async ({ request }: LoaderFunctionArgs) => {
const url = new URL(request.url);
const selectedTag = url.searchParams.get("tag") ?? undefined;
return json(
await promiseHash({
articles: throwAnyErrors(
GET("/articles", { params: { query: { tag: selectedTag } } }),
),
tags: throwAnyErrors(GET("/tags")),
}),
);
};
```
--------------------------------
### Redux Store Setup and Global Types in TypeScript
Source: https://feature-sliced.github.io/documentation/docs/guides/examples/types
Demonstrates setting up a Redux store with combined reducers and defining global types `RootState` and `AppDispatch` for typed Redux hooks. This approach uses TypeScript's global type declaration to overcome import restrictions between layers.
```typescript
import { combineReducers, createStore } from "redux";
import { songReducer } from "entities/song";
import { artistReducer } from "entities/artist";
const rootReducer = combineReducers({
songs: songReducer,
artists: artistReducer
});
const store = createStore(rootReducer);
declare type RootState = ReturnType;
declare type AppDispatch = typeof store.dispatch;
```
```typescript
import { useDispatch, useSelector, type TypedUseSelectorHook } from "react-redux";
// Assuming RootState and AppDispatch are declared globally or imported
// declare type RootState = ...;
declare type AppDispatch = any; // Placeholder if not globally declared
export const useAppDispatch = useDispatch.withTypes();
export const useAppSelector: TypedUseSelectorHook = useSelector;
```
--------------------------------
### Register Route Definition (TypeScript/React)
Source: https://feature-sliced.github.io/documentation/docs/get-started/tutorial
Defines the /register route by importing and exporting the RegisterPage component and the register API action. This connects the UI to the backend logic for user registration.
```typescript
import { RegisterPage, register } from "pages/sign-in";
export { register as action };
export default RegisterPage;
```
--------------------------------
### Article Preview Component (TypeScript)
Source: https://feature-sliced.github.io/documentation/docs/get-started/tutorial
Defines the ArticlePreview component which renders a single article's summary, author information, and metadata. It uses Remix's Link for navigation and formats the date for display. Dependencies include '@remix-run/react' and 'shared/api'.
```typescript
import { Link } from "@remix-run/react";
import type { Article } from "shared/api";
interface ArticlePreviewProps {
article: Article;
}
export function ArticlePreview({ article }: ArticlePreviewProps) {
return (
);
}
```
--------------------------------
### Create and Use Custom API Client (TypeScript)
Source: https://feature-sliced.github.io/documentation/docs/guides/tech/with-react-query
Defines a reusable `ApiClient` class in TypeScript for standardized interaction with APIs. It handles GET and POST requests, response parsing, and error management. The client is initialized with a base URL and a default instance is exported.
```typescript
import { API_URL } from "@/shared/config";
export class ApiClient {
private baseUrl: string;
constructor(url: string) {
this.baseUrl = url;
}
async handleResponse(response: Response): Promise {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
try {
return await response.json();
} catch (error) {
throw new Error("Error parsing JSON response");
}
}
public async get(
endpoint: string,
queryParams?: Record,
): Promise {
const url = new URL(endpoint, this.baseUrl);
if (queryParams) {
Object.entries(queryParams).forEach(([key, value]) => {
url.searchParams.append(key, value.toString());
});
}
const response = await fetch(url.toString(), {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
return this.handleResponse(response);
}
public async post>(
endpoint: string,
body: TData,
): Promise {
const response = await fetch(`${this.baseUrl}${endpoint}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
return this.handleResponse(response);
}
}
export const apiClient = new ApiClient(API_URL);
```
--------------------------------
### Direct Mutation Usage with useMutation (React Query)
Source: https://feature-sliced.github.io/documentation/docs/guides/tech/with-react-query
Shows how to directly use React Query's `useMutation` hook within a component to handle data mutations. This example demonstrates a simple case of creating a post, including managing loading states.
```javascript
const { mutateAsync, isPending } = useMutation({
mutationFn: postApi.createPost, // Assuming postApi.createPost is defined elsewhere
});
```