javascriptreactjsfilereaderweb-share

Trying to create a button that handles an upload and a web share api function at the same time


I am trying to create a single button in my React app that allows me to upload an image, and then using the web share api, share the uploaded image to whatever the user wants to...

My issue is, I cannot seem to execute the two one after the other. Upload first, share second.

I have tried maybe using a setTimeout, or a setInterval, or waiting for a state to equal true, but I cant seem to figure it out.

Here is my code:



import { useRef, useState } from "react";
import { toBlob } from "html-to-image";
import Button from '@mui/material/Button';
import { styled } from '@mui/material/styles';

import IconButton from '@mui/material/IconButton';
import PhotoCamera from '@mui/icons-material/PhotoCamera';
import Stack from '@mui/material/Stack';

import '../styles/styles.css'

export default function Model() {

  const [image, setImage] = useState(null);

  const handleUpload = (e) => {
    const file = e.target.files[0];
    const reader = new FileReader();
    reader.onloadend = () => {
      setImage(reader.result);
    }
    reader.readAsDataURL(file);
  }


  const handleShare = async () => {
    console.log=("share clicked")
    const base64url = image
    const blob = await (await fetch(base64url)).blob();
    const file = new File([blob], 'fileName.png', { type: blob.type });
    navigator.share({
      title: 'Test Title',
      text: ' Experience',
      files: [file],
    })
  }

  const ColorButton = styled(Button)(({ theme }) => ({
    borderRadius: 50,
    border: '4px solid',
    borderColor: '#F0B152',
    backgroundColor: '#000000',
    color: 'white',
  }));

  return (
    <div className="App">


        <Button variant="contained" component="label">
          Upload
          <input hidden accept="image/*" multiple type="file" onChange={handleUpload} onClick={handleShare}/>
        </Button>
    </div>
  );
}

Solution

  • You can move the handleShare function inside an useEffect hook and add image as a dependency. So that every time the setImage function is executed the useEffect hook will trigger the handleShare function.

    import { useEffect, useState } from "react";
    import Button from "@mui/material/Button";
    
    export default function App() {
      const [image, setImage] = useState(null);
    
      useEffect(() => {
        if (image) {
          const handleShare = async () => {
            const base64url = image;
            const blob = await (await fetch(base64url)).blob();
            const file = new File([blob], "fileName.png", { type: blob.type });
            navigator.share({
              title: "Test Title",
              text: " Experience",
              files: [file]
            });
          };
    
          handleShare();
        }
      }, [image]);
      
      const handleUpload = (e) => {
        const file = e.target.files[0];
        const reader = new FileReader();
        reader.onloadend = () => {
          setImage(reader.result);
        };
        reader.readAsDataURL(file);
      };
    
      return (
        <div className="App">
          <Button variant="contained" component="label">
            Upload
            <input
              hidden
              accept="image/*"
              multiple
              type="file"
              onChange={handleUpload}
            />
          </Button>
        </div>
      );
    }