3

I have <input type="file" /> and want to trigger .click() on that input. Everything works fine in chrome, firefox, edge but problem exists in safari.

When I click on button to trigger inputFile.current.click() - it works. But when it happens inside useEffect/useLayoutEffect - it doesn't work (I've tried adding timeouts and it also didn't help).

Working example to reproduce problem: https://codesandbox.io/s/react-hooks-counter-demo-forked-49n2t?file=/src/index.js

As less code as possible to present problem

import React, { useCallback, useState, useEffect, useLayoutEffect, useRef } from 'react';
import { useRecoilState } from 'recoil';
import { requestedNewCanvasObjAtom } from '../SlidesState/slidesAtoms';

const Slide: React.FC = () => {
  const [trigger, setTrigger] = useState(false);
  const [requestedNewCanvasObj] = useRecoilState(requestedNewCanvasObjAtom);
  const inputFile = useRef(null);

  useLayoutEffect(() => {
    console.log('IT IS HERE WHEN EXPECTED BUT IT DOES NOT WORK TOO');
    inputFile.current.click();
  }, [requestedNewCanvasObj]);

  useLayoutEffect(() => {
    console.log('IT WORKS');
    inputFile.current.click();
  }, [trigger]);

  const triggerUpload = useCallback(() => {
    if (inputFile && inputFile.current) {
      console.log('IT WORKS');
      inputFile.current.click();
    }
  }, []);

  return (
    <>
      <button onClick={triggerUpload}>Click</button>
      <button onClick={() => setTrigger(true)}>Update state to trigger input click</button>
      <input type="file" id="file" ref={inputFile} />
    </>
  );
};

export default Slide;

THIS QUESTION WAS UPDATED - simplified problem without recoil was solved by useLayoutEffect but turns out that my problem is more complex

Żywy
  • 393
  • 2
  • 12

2 Answers2

5

The on click event is fired but the finder doesn't show up. Use useLayoutEffect. It fires synchronously after all DOM mutations:

  useLayoutEffect(()=> {
    if (inputRef && inputRef.current) {
      inputRef.current.click();
    }
  }, [count])

In other browsers like Chrome, useEffects and useLayoutEffect will work to show the finder. But in Safari, only the useLayoutEffect will work.

lissettdm
  • 12,267
  • 1
  • 18
  • 39
0

@Żywy Add id to input and add label with htmlFor attribute.

Important: Input element must not be inside the label

Check this codepen: https://codesandbox.io/s/react-hooks-counter-demo-forked-7bnut7?file=/src/index.js (click on the red text)

kanapka94
  • 51
  • 4