---
url: /docs/integrations/react.md
description: How to use Electric with React.
---
# React
React is a popular library for building declarative, component-based UI.
## Electric and React
Electric has first-class support for React. We maintain a [react-hooks](https://github.com/electric-sql/electric/tree/main/packages/react-hooks) package that provides a number of [React Hooks](https://react.dev/reference/react/hooks) to bind Shape data to your components.
## How to use
### Install
The package is published on NPM as [`@electric-sql/react`](https://www.npmjs.com/package/@electric-sql/react). Install using e.g.:
```shell
npm i @electric-sql/react
```
### Best Practice: Use API Endpoints
:::tip Recommended Pattern
Always proxy Electric requests through your backend API for production applications. This provides security, authorization, and a clean API interface.
:::
```tsx
// ✅ Recommended: Clean API pattern
import { useShape } from '@electric-sql/react'
const MyComponent = () => {
const { isLoading, data } = useShape<{ title: string }>({
url: `http://localhost:3001/api/items`, // Your API endpoint
})
if (isLoading) {
return
Loading ...
}
return (
{data.map((item) => (
{item.title}
))}
)
}
```
**→ See the [authentication guide](/docs/guides/auth) for complete proxy implementation with streaming, error handling, and authorization.**
### `useShape`
[`useShape`](https://github.com/electric-sql/electric/blob/main/packages/react-hooks/src/react-hooks.tsx#L131) binds a materialised [Shape](/docs/api/clients/typescript#shape) to a state variable.
#### Direct Connection (Development Only)
For development, you can connect directly to Electric:
```tsx
// ⚠️ Development only - exposes database structure
import { useShape } from '@electric-sql/react'
const MyComponent = () => {
const { isLoading, data } = useShape<{ title: string }>({
url: `http://localhost:3000/v1/shape`,
params: {
table: 'items',
},
})
if (isLoading) {
return Loading ...
}
return (
{data.map((item) => (
{item.title}
))}
)
}
```
You can also include additional PostgreSQL-specific parameters:
```tsx
const MyFilteredComponent = () => {
const { isLoading, data } = useShape<{ id: number; title: string }>({
url: `http://localhost:3000/v1/shape`,
params: {
table: 'items',
where: "status = 'active'",
columns: ['id', 'title'],
},
})
// ...
}
```
`useShape` takes the same options as [ShapeStream](/docs/api/clients/typescript#options). The return value is a `UseShapeResult`:
```tsx
export interface UseShapeResult = Row> {
/**
* The array of rows that make up the materialised Shape.
* @type {T[]}
*/
data: T[]
/**
* The Shape instance used by this useShape
* @type {Shape}
*/
shape: Shape
/** True during initial fetch. False afterwise. */
isLoading: boolean
/** Unix time at which we last synced. Undefined when `isLoading` is true. */
lastSyncedAt?: number
/** Unix time at which we last synced. Undefined when `isLoading` is true. */
isError: boolean
error: Shape[`error`]
}
```
### `preloadShape`
[`preloadShape`](https://github.com/electric-sql/electric/blob/main/packages/react-hooks/src/react-hooks.tsx#L17) is useful to call in route loading functions or elsewhere when you want to ensure Shape data is loaded before rendering a route or component.
```tsx
// ✅ Production pattern with API proxy
export const clientLoader = async () => {
return await preloadShape({
url: `http://localhost:3001/api/items`,
})
}
```
For development, you can connect directly:
```tsx
// ⚠️ Development only
export const devLoader = async () => {
return await preloadShape({
url: `http://localhost:3000/v1/shape`,
params: {
table: 'items',
},
})
}
```
It takes the same options as [ShapeStream](/docs/api/clients/typescript#options).
### `getShapeStream`
[`getShapeStream`](https://github.com/electric-sql/electric/blob/main/packages/react-hooks/src/react-hooks.tsx#L30) get-or-creates a `ShapeStream` off the global cache.
```tsx
// ✅ Production pattern
const itemsStream = getShapeStream- ({
url: `http://localhost:3001/api/items`,
})
```
This allows you to avoid consuming multiple streams for the same shape log.
### `getShape`
[`getShape`](https://github.com/electric-sql/electric/blob/main/packages/react-hooks/src/react-hooks.tsx#L49) get-or-creates a `Shape` off the global cache.
```tsx
// ✅ Production pattern
const itemsShape = getShape
- ({
url: `http://localhost:3001/api/items`,
})
```
This allows you to avoid materialising multiple shapes for the same stream.
### How to abort a shape subscription — `AbortController`
If you'd like to abort the shape's subscription to live updates e.g. after unmounting a component or navigating away from a route, you can use the [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController).
The following is a simple example which aborts the subscription when the component is unmounted.
```tsx
function MyComponent() {
const [controller, _] = useState(new AbortController())
const { data } = useShape({
...
signal: controller.signal
})
useEffect(() => {
return () => {
// Live updates are now disabled.
controller.abort()
}
}, [])
...
}
```
Note that if you have multiple components using the same component, this will stop updates for all subscribers. Which is probably not what you want. We plan to add a better API for unsubscribing from updates & cleaning up shapes that are no longer needed. If interested, please file an issue to start a discussion.