DEV Community

Denys
Denys

Posted on

1 1

react-dropzone with web worker

Motivation

Once I had a weird experience with large images and some stuff like images and react-dropzone. It was too laggy with large ones and it blocked some UI elements.

Prerequisites

  • react and stuff chained with it
  • react-dropzone

Problematic

I have written an example with the default preset for react-dropzone and just trying to upload some large img.

First code block (such as default preset):

import { useCallback, useState } from 'react'
import { useDropzone } from 'react-dropzone'

export const Dropzone = () => {
    const [state, setState] = useState<string | undefined>(undefined)
    const onDrop = useCallback((acceptedFiles: File[]) => {
        acceptedFiles.forEach((file) => {
            const reader = new FileReader()

            reader.onload = () => {
                const result = reader.result as any

                setState(result)
            }

            reader.readAsDataURL(file)
        })
    }, [])

    const { getRootProps, getInputProps } = useDropzone({ onDrop })

    return (
        <div {...getRootProps()}>
            <input {...getInputProps()} />
            <p>Drag 'n' drop some files here, or click to select files</p>
            {state && <img src={state} style={{ width: 200, height: 200 }} />}
        </div>
    )
}

Enter fullscreen mode Exit fullscreen mode

We can try to use input while we trying to upload an image and ... it's gone.

So I tried many things and maybe u can provide ur own solutions to comments or will create another article about it, will appreciate it.

Solution

The solution is to use Web Worker to unload our operation.
The preload by new Image() does not work.
Web Worker has no Image at all, though.

worker.js

onmessage = async function (event) {
    const response = await fetch(event.data.result)
    const blob = await response.blob()
    postMessage(URL.createObjectURL(blob))
}
Enter fullscreen mode Exit fullscreen mode

index.tsx

import { useCallback, useEffect, useState } from 'react'
import { useDropzone } from 'react-dropzone'

export const Dropzone = () => {
    const [state, setState] = useState<string | undefined>(undefined)
    const [worker, setWorker] = useState<Worker | null>(null)
    const onDrop = useCallback(
        (acceptedFiles: File[]) => {
            acceptedFiles.forEach((file) => {
                const reader = new FileReader()

                reader.onload = () => {
                    const result = reader.result as string
                    if (worker) {
                        worker.postMessage({ result })
                    }
                }

                reader.readAsDataURL(file)
            })
        },
        [worker]
    )

    const { getRootProps, getInputProps } = useDropzone({ onDrop })

    useEffect(() => {
        const workerInstance = new Worker(new URL('worker.js', import.meta.url))
        workerInstance.onmessage = function ({ data }) {
            setState(data)
        }

        setWorker(workerInstance)

        return () => workerInstance.terminate()
    }, [])
    return (
        <div {...getRootProps()}>
            <input {...getInputProps()} />
            <p>Drag 'n' drop some files here, or click to select files</p>
            {state && <img src={state} style={{ width: 200, height: 200 }} />}
        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

Sentry blog image

How I fixed 20 seconds of lag for every user in just 20 minutes.

Our AI agent was running 10-20 seconds slower than it should, impacting both our own developers and our early adopters. See how I used Sentry Profiling to fix it in record time.

Read more

Top comments (1)

Collapse
 
lotfijb profile image
Lotfi Jebali

Thanks for sharing

nextjs tutorial video

Youtube Tutorial Series 📺

So you built a Next.js app, but you need a clear view of the entire operation flow to be able to identify performance bottlenecks before you launch. But how do you get started? Get the essentials on tracing for Next.js from @nikolovlazar in this video series 👀

Watch the Youtube series

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay