Search code examples
reactjsreact-ref

Why is my fileRef not opening the element I'm referencing onClick


I want to upload a file by clicking the image element.

I have an Input element of file type with a useRef. I'm referencing the useRef in the img Onclick but it's not opening the file selector.

I tested it by clicking the input file type directly and it works, but it won't work when I'm referencing it from the img element.

I need to be able to open the file navigator by clicking the image that's referencing the Input, not the Input of file type

import { useContext, useEffect, useState, useRef } from "react";
import {
  Box,
  Button,
  Card,
  FormControl,
  Input,
  TextField,
  Typography,
} from "@mui/material";
import profilePlaceholder from "../../assets/images/imagePH.png";
import { signOut } from "firebase/auth";
import { auth } from "../../environments/environment";
import { EditProfileModal } from "./EditProfileModal";
import useGetUserProfile from "../../hooks/useGetUserProfile";
import { UserProfileContext } from "../../Context/UserProfileContext";
import useUploadImage from "../../hooks/useUploadImage";

export const ProfileForm = () => {
  const [showLogin, setShowLogin] = useState(false);
  const { userProfile, setUserProfile } = useGetUserProfile();
  const {userProfileContext, setUserProfileContext} = useContext(UserProfileContext)
  const { handleImageUpload } = useUploadImage();
  const fileRef = useRef<HTMLInputElement>(null);
  
  useEffect(() => {
    if (userProfile) {
      setUserProfileContext(userProfile);
    }
  }, [userProfile, setUserProfile, setUserProfileContext]);

  return (
    <>
      <form noValidate>
        <Box display="flex" justifyContent="flex-end" p={2}>
          <Button
            variant="contained"
            color="secondary"
            onClick={async () => {
              await signOut(auth);
              window.location.href = "/login";
            }}
            sx={{
              borderRadius: "50%",
              width: 80,
              height: 80,
            }}>
            <span role="img" aria-label="logout">
              Logout
            </span>
          </Button>
        </Box>
        <Box mt={0} display="flex" justifyContent="center">
          <img
            src={profilePlaceholder}
            alt="Profile Placeholder"
            style={{ maxWidth: "100%", height: "auto" }}
            onClick={() => {
              fileRef.current?.click();
              console.log("click");
            }}
          />
          <Input
          type='file'
          ref={fileRef}
          style={{ display: "none" }}
          />
          <Box sx={{ flexDirection: "column" }}>
            <Typography
              ml={2}
              fontSize={{ base: "sm", md: "lg" }}
              color="white"
              sx={{ fontSize: "2rem" }}>
              {userProfileContext?.username || ""}
            </Typography>
            <Button
              variant="contained"
              size="small"
              onClick={() => setShowLogin(true)}
              sx={{ marginTop: 2, background: "white", color: "black" }}>
              Edit Profile
            </Button>
          </Box>
        </Box>
      </form>
      <EditProfileModal show={showLogin} close={() => setShowLogin(false)} />
    </>
  );

Solution

  • According to the docs, ref is passed to the Root element (div) so you need to use inputRef prop to pass ref directly to the input element.

    You need to change this:

    <Input
      type='file'
      ref={fileRef}
      style={{ display: "none" }}
    />
    

    To this:

    <Input
      type='file'
      inputRef={fileRef}
      style={{ display: "none" }}
    />