diff --git a/examples/react-example/App.jsx b/examples/react-example/App.jsx
deleted file mode 100644
index 8f1460fcb..000000000
--- a/examples/react-example/App.jsx
+++ /dev/null
@@ -1,114 +0,0 @@
-/* eslint-disable */
-import React from'react'
-import Uppy from'@uppy/core'
-import Tus from'@uppy/tus'
-import GoogleDrive from '@uppy/google-drive'
-import Webcam from '@uppy/webcam'
-import RemoteSources from '@uppy/remote-sources'
-import { Dashboard, DashboardModal, DragDrop, ProgressBar, FileInput } from'@uppy/react'
-
-import '@uppy/core/dist/style.css'
-import '@uppy/dashboard/dist/style.css'
-import '@uppy/drag-drop/dist/style.css'
-import '@uppy/file-input/dist/style.css'
-import '@uppy/progress-bar/dist/style.css'
-
-export default class App extends React.Component {
- constructor (props) {
- super(props)
-
- this.state = {
- showInlineDashboard: false,
- open: false
- }
-
- this.uppy = new Uppy({ id: 'uppy1', autoProceed: true, debug: true })
- .use(Tus, { endpoint: 'https://tusd.tusdemo.net/files/' })
- .use(Webcam)
- .use(RemoteSources, { companionUrl: 'https://companion.uppy.io', sources: ['GoogleDrive', 'Box', 'Dropbox', 'Facebook', 'Instagram', 'OneDrive', 'Unsplash', 'Zoom', 'Url'],
- })
-
- this.uppy2 = new Uppy({ id: 'uppy2', autoProceed: false, debug: true })
- .use(Tus, { endpoint: 'https://tusd.tusdemo.net/files/' })
-
- this.handleModalClick = this.handleModalClick.bind(this)
- }
-
- componentWillUnmount () {
- this.uppy.close({ reason: 'unmount' })
- this.uppy2.close({ reason: 'unmount' })
- }
-
- handleModalClick () {
- this.setState({
- open: !this.state.open
- })
- }
-
- render () {
- const { showInlineDashboard } = this.state
- return (
-
-
React Examples
-
-
Inline Dashboard
-
- {showInlineDashboard && (
-
- )}
-
-
Modal Dashboard
-
-
- this.setState({ open: false })}
- />
-
-
-
Drag Drop Area
-
-
-
Progress Bar
-
-
-
File Input
-
-
- )
- }
-}
diff --git a/examples/react-example/App.tsx b/examples/react-example/App.tsx
new file mode 100644
index 000000000..e7636f1db
--- /dev/null
+++ b/examples/react-example/App.tsx
@@ -0,0 +1,49 @@
+/* eslint-disable */
+import React from 'react'
+import Uppy from '@uppy/core'
+import Tus from '@uppy/tus'
+import Webcam from '@uppy/webcam'
+import RemoteSources from '@uppy/remote-sources'
+import { Dashboard, useUppyState } from '@uppy/react'
+
+import '@uppy/core/dist/style.css'
+import '@uppy/dashboard/dist/style.css'
+import '@uppy/drag-drop/dist/style.css'
+import '@uppy/file-input/dist/style.css'
+import '@uppy/progress-bar/dist/style.css'
+
+const metaFields = [
+ { id: 'license', name: 'License', placeholder: 'specify license' },
+]
+
+function createUppy() {
+ return new Uppy({ restrictions: { requiredMetaFields: ['license'] } })
+ .use(Tus, { endpoint: 'https://tusd.tusdemo.net/files/' })
+ .use(Webcam)
+ .use(RemoteSources, {
+ companionUrl: 'https://companion.uppy.io',
+ })
+}
+
+export default function App() {
+ // IMPORTANT: passing an initaliser function to useState
+ // to prevent creating a new Uppy instance on every render.
+ // useMemo is a performance hint, not a guarantee.
+ const [uppy] = React.useState(createUppy)
+ // You can access state reactively with useUppyState
+ const fileCount = useUppyState(
+ uppy,
+ (state) => Object.keys(state.files).length,
+ )
+ const totalProgress = useUppyState(uppy, (state) => state.totalProgress)
+ // Also possible to get the state of all plugins.
+ const plugins = useUppyState(uppy, (state) => state.plugins)
+
+ return (
+ <>
+ File count: {fileCount}
+ Total progress: {totalProgress}
+
+ >
+ )
+}
diff --git a/examples/react-example/index.html b/examples/react-example/index.html
index 7a885b5b2..c1ea87c94 100644
--- a/examples/react-example/index.html
+++ b/examples/react-example/index.html
@@ -8,6 +8,6 @@
-
+