0

I'm trying to create a custom useForm hook which will update an object and handle multiple input types. When I upload an image, I grab the first image and save it to value BUT when I setState with setInputs, the image value in the inputs object is null even though the value is the File object (as I've console logged it before).

I'm not sure if this is a typescript specific error. I tried setting profileImage to be any without any impact.

EDIT: The image is being uploaded correctly, but not displaying when using JSON.stringify as mentioned in the comments... so no actual error.

// Hook usage
const { inputs, handleInput } = useForm<{
  name: string
  description: string
  profileImage: File | null
}>({
  name: "",
  description: "",
  profileImage: null,
})
// Form Input
<input
  onChange={handleInput}
  type="file"
  accept="image/*"
  id="profileImage"
  name="profileImage"
/>
// useForm hook
export type FormEvent = React.ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement>

export default function useForm<T extends { [key: string]: any }>(initial: T = {} as T) {
  const [inputs, setInputs] = useState<T>(initial)

  const handleInput = (e: FormEvent) => {
    let { value, name, type }: { value: any; name: string; type: string } = e.target
    if (type === "number") {
      value = parseInt(value)
    } else if (type === "file") {
      value = (e.target as HTMLInputElement).files![0]
    }
    setInputs({ ...inputs, [name]: value })
  }

  return { inputs, setInputs, handleInput }
}

Ibaeni
  • 55
  • 10
  • Testing it out more, I create a separate variable `const [file, setFile] = useState<{ profileImage: File | null }>({ profileImage: null })` and updating it with `setFile({ profileImage: value })` has no affect as well (profileImage is still null even though value is the File). – Ibaeni Apr 23 '21 at 15:44
  • How did you conclude that it's null? where are checking for the value? – ksankar Apr 23 '21 at 16:38
  • I omitted the console logs, but I log out inputs after the update and am displaying it in my component with JSON.stringify(inputs) – Ibaeni Apr 23 '21 at 18:06
  • JSON.stringify won't show the file object even if it's there. Try logging `file.name`. I've updated the sandbox below to demonstrate how JSON.stringify doesn't show it. For more info read: https://stackoverflow.com/questions/53277935/json-stringify-function-is-replacing-the-file-object-with-an-empty-one – ksankar Apr 23 '21 at 18:24
  • @ksankar You're absolutely right, the value is being set, just not displaying using JSON.stringify. Geez, I feel silly. Thanks for the clarification! – Ibaeni Apr 23 '21 at 22:12

1 Answers1

0

I reproduced a simplified version of your example, just handling the file case. The upload onChange action is handled by the hook, file object is returned and name gets displayed on the HTML.

https://codesandbox.io/s/condescending-mcclintock-qs3c1?file=/src/App.js

function useForm(init) {
  const [file, setFile] = React.useState(init);
  const handleFileInput = (e) => {
    setFile(e.target.files[0]);
  };
  return {file, handleFileInput};
}


export default function App() {
  const {file, handleFileInput } = useForm(null);

  console.log('file', file);
  return (
    <div className="App">
      <h3>File Upload Test</h3>
      <input type="file" onChange={handleFileInput} />
      <div> File Info: {file && file.name} </div>
    </div>
  );
}
ksankar
  • 465
  • 7
  • 13