mirror of
https://github.com/transloadit/uppy.git
synced 2026-07-18 00:55:35 +00:00
228 lines
6.1 KiB
Text
228 lines
6.1 KiB
Text
---
|
||
slug: /react
|
||
---
|
||
|
||
import Tabs from '@theme/Tabs';
|
||
import TabItem from '@theme/TabItem';
|
||
|
||
# React
|
||
|
||
[React][] components for the Uppy UI plugins and a `useUppyState` hook.
|
||
|
||
## Install
|
||
|
||
<Tabs>
|
||
<TabItem value="npm" label="NPM" default>
|
||
|
||
```shell
|
||
npm install @uppy/react
|
||
```
|
||
|
||
</TabItem>
|
||
|
||
<TabItem value="yarn" label="Yarn">
|
||
|
||
```shell
|
||
yarn add @uppy/react
|
||
```
|
||
|
||
</TabItem>
|
||
</Tabs>
|
||
|
||
:::note
|
||
|
||
You also need to install the UI plugin you want to use. For instance,
|
||
`@uppy/dashboard`.
|
||
|
||
:::
|
||
|
||
## Use
|
||
|
||
`@uppy/react` exposes component wrappers for `Dashboard`, `DragDrop`, and all
|
||
other UI elements. The components can be used with either [React][] or
|
||
API-compatible alternatives such as [Preact][].
|
||
|
||
:::caution
|
||
|
||
If you find yourself writing many instances of `useState` and `useEffect` to
|
||
achieve something with Uppy in React, you are most likely breaking React best
|
||
practices. Consider reading
|
||
“[You Might Not Need an Effect](https://react.dev/learn/you-might-not-need-an-effect)”
|
||
and looking at our examples below.
|
||
|
||
:::
|
||
|
||
### Components
|
||
|
||
The following components are exported from `@uppy/react`:
|
||
|
||
- `<Dashboard />` renders [`@uppy/dashboard`](/docs/dashboard)
|
||
- `<DragDrop />` renders [`@uppy/drag-drop`](/docs/drag-drop)
|
||
- `<ProgressBar />` renders [`@uppy/progress-bar`](/docs/progress-bar)
|
||
- `<StatusBar />` renders [`@uppy/status-bar`](/docs/status-bar)
|
||
|
||
{/* prettier-ignore */}
|
||
{/* Commented out until the hook is live
|
||
|
||
### Hooks
|
||
|
||
`useUppyState(uppy, selector)`
|
||
|
||
Use this hook when you need to access Uppy’s state reactively. Most of the
|
||
times, this is needed if you are building a custom UI for Uppy in React.
|
||
|
||
```js
|
||
// IMPORTANT: passing an initializer function to prevent Uppy from being reinstantiated on every render.
|
||
const [uppy] = useState(() => new Uppy());
|
||
|
||
const files = useUppyState(uppy, (state) => state.files);
|
||
const totalProgress = useUppyState(uppy, (state) => state.totalProgress);
|
||
// We can also get specific plugin state.
|
||
// Note that the value on `plugins` depends on the `id` of the plugin.
|
||
const metaFields = useUppyState(
|
||
uppy,
|
||
(state) => state.plugins?.Dashboard?.metaFields,
|
||
);
|
||
```
|
||
|
||
You can see all the values you can access on the
|
||
[`State`](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/core/types/index.d.ts#L190)
|
||
type. If you are accessing plugin state, you would have to look at the types of
|
||
the plugin.
|
||
|
||
\*/}
|
||
|
||
## Examples
|
||
|
||
### Example: basic component
|
||
|
||
Here we have a basic component which ties Uppy’s state to the component. This
|
||
means you can render multiple instances. But be aware that as your component
|
||
unmounts, for instance because the user navigates to a different page, Uppy’s
|
||
state will be lost and uploads will stop.
|
||
|
||
:::note
|
||
|
||
If you render multiple instances of Uppy, make sure to give each instance a
|
||
unique `id`.
|
||
|
||
:::
|
||
|
||
```js
|
||
import React, { useEffect, useState } from 'react';
|
||
import Uppy from '@uppy/core';
|
||
import Webcam from '@uppy/webcam';
|
||
import { Dashboard } from '@uppy/react';
|
||
|
||
import '@uppy/core/dist/style.min.css';
|
||
import '@uppy/dashboard/dist/style.min.css';
|
||
import '@uppy/webcam/dist/style.min.css';
|
||
|
||
function Component() {
|
||
// IMPORTANT: passing an initializer function to prevent Uppy from being reinstantiated on every render.
|
||
const [uppy] = useState(() => new Uppy().use(Webcam));
|
||
|
||
return <Dashboard uppy={uppy} plugins={['Webcam']} />;
|
||
}
|
||
```
|
||
|
||
### Example: keep Uppy state and uploads while navigating between pages
|
||
|
||
When you want Uppy’s state to persist and keep uploads running between pages,
|
||
you can
|
||
[lift the state up](https://react.dev/learn/sharing-state-between-components#lifting-state-up-by-example).
|
||
|
||
```js
|
||
import React, { useState, useEffect } from 'react';
|
||
import Uppy from '@uppy/core';
|
||
import { Dashboard } from '@uppy/react';
|
||
|
||
function Page1() {
|
||
// ...
|
||
}
|
||
|
||
function Page2({ uppy }) {
|
||
return (
|
||
<>
|
||
<p>{totalProgress}</p>
|
||
<Dashboard id="dashboard" uppy={uppy} />
|
||
</>
|
||
);
|
||
}
|
||
|
||
export default function App() {
|
||
// keeping the uppy instance alive above the pages the user can switch during uploading
|
||
const [uppy] = useState(() => new Uppy());
|
||
|
||
return (
|
||
// Add your router here
|
||
<>
|
||
<Page1 />
|
||
<Page2 uppy={uppy} />
|
||
</>
|
||
);
|
||
}
|
||
```
|
||
|
||
### Example: updating Uppy’s options dynamically based on props
|
||
|
||
```js
|
||
// ...
|
||
function Component(props) {
|
||
// IMPORTANT: passing an initializer function to prevent the state from recreating.
|
||
const [uppy] = useState(() => new Uppy().use(Webcam));
|
||
|
||
useEffect(() => {
|
||
uppy.setOptions({ restrictions: props.restrictions });
|
||
}, [props.restrictions]);
|
||
|
||
useEffect(() => {
|
||
uppy.getPlugin('Webcam').setOptions({ modes: props.webcamModes });
|
||
}, [props.webcamModes]);
|
||
|
||
return <Dashboard uppy={uppy} plugins={['Webcam']} />;
|
||
}
|
||
```
|
||
|
||
### Example: dynamic params and signature for Transloadit
|
||
|
||
When you go to production always make sure to set the `signature`. **Not using
|
||
[Signature Authentication](https://transloadit.com/docs/topics/signature-authentication/)
|
||
can be a security risk**. Signature Authentication is a security measure that
|
||
can prevent outsiders from tampering with your Assembly Instructions.
|
||
|
||
Generating a signature should be done on the server to avoid leaking secrets. In
|
||
React, this could get awkward with a `fetch` in a `useEffect` and setting it to
|
||
`useState`. Instead, it’s easier to use the
|
||
[`assemblyOptions`](/docs/transloadit#assemblyoptions) option to `fetch` the
|
||
params.
|
||
|
||
```js
|
||
// ...
|
||
function createUppy(userId) {
|
||
return new Uppy({ meta: { userId } }).use(Transloadit, {
|
||
async assemblyOptions(file) {
|
||
// You can send meta data along for use in your template.
|
||
// https://transloadit.com/docs/topics/assembly-instructions/#form-fields-in-instructions
|
||
const body = JSON.stringify({ userId: file.meta.userId });
|
||
const res = await fetch('/transloadit-params', { method: 'POST', body });
|
||
return response.json();
|
||
},
|
||
});
|
||
}
|
||
|
||
function Component({ userId }) {
|
||
// IMPORTANT: passing an initializer function to prevent Uppy from being reinstantiated on every render.
|
||
const [uppy] = useState(() => createUppy(userId));
|
||
|
||
useEffect(() => {
|
||
if (userId) {
|
||
// Adding to global `meta` will add it to every file.
|
||
uppy.setOptions({ meta: { userId } });
|
||
}
|
||
}, [uppy, userId]);
|
||
}
|
||
```
|
||
|
||
[react]: https://facebook.github.io/react
|
||
[preact]: https://preactjs.com/
|