1

I am attempting to relay data between a file uploader and a table, using a shared ancestor. I have a file uploader but once I add my JSON file I receive the error TypeError: setProductState is not a function.

When I console log my inputJson file it goes though, but when I apply setProductState and input my file I receive this error.

Based on what I've read I don't need a bind because I am using arrow syntax, but I possibly might need a 'this'.

Any thoughts or critiques are welcome.

function FileUploader({ productState, setProductState }) {

  const onDrop = useCallback((acceptedFiles) => {
   // this.setProductState = this.setProductState.bind(this); tried
    acceptedFiles.forEach((file) => {
      const reader = new FileReader()
      reader.onload  = () => {
        const inputJson =
          this.inputJson = inputJson //tried
          JSON.parse(reader.result)
          setProductState(inputJson); //console.log goes through
        }
      reader.readAsText(file)
    })

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

  return (
    <div {...getRootProps({style})}>
      <input {...getInputProps()} value={productState}/>
      <p>Drag files here, or click to browse</p>
    </div>
  )
}

Ancestor.js

import React, { useState } from 'react'
import FileUploader from './FileUploader'
import Table from './Table'

const Ancestor = () => {
    const [products, setProducts] = useState({});
    return <>
      <FileUploader productState={products} setProductState={setProducts} />
      <Table productState={products} />
    </>;
  }

export default Ancestor;

Aly Hoop
  • 115
  • 9
  • 1
    You could start with checking what exactly `setProductState` is. If its not a function or if its _undefined_, check if you have passed props correctly. – kind user Oct 27 '20 at 22:55
  • 1
    Show the code for the parent component. Where is SetProductState defined? – Benjamin Oct 27 '20 at 23:03
  • @Benjamin I have added the parent component. It is defined in an ancestor. Thank you both for your suggestions. – Aly Hoop Oct 28 '20 at 00:40

1 Answers1

1

I believe you may be confused about how this keyword works. Inside your FileUploader component, this will be a reference to FileUploader, and not to Ancestor.

You don't need a reference to Ancestor, because you are passing products and setProducts as props. This is the proper way to do it.

Also, you probably don't mean to do a forEach on acceptedFiles, since it appears that you only desire one file, correct?

Give this a try.

function FileUploader(props) {
  // Define an onDrop function to handle drop events
  const onDrop = useCallback((acceptedFiles) => {
    // Get the first file in the list of acceptedFiles
    const file = acceptedFiles[0];

    // Create a FileReader
    const reader = new FileReader();

    // Create a function to handle the reader onload event
    reader.onload = () => {
      // JSON parse the result from read as text
      let parsed = JSON.parse(reader.result);
      // Call the setProductState function from Ancestor component
      props.setProductState(parsed);
    };

    // Read the file, triggering the onload event handler
    reader.readAsText(file);
  }, []);

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

  return (
    <div {...getRootProps({ style })}>
      <input {...getInputProps()} value={props.productState} />
      <p>Drag files here, or click to browse</p>
    </div>
  );
}
Benjamin
  • 3,428
  • 1
  • 15
  • 25
  • I appreciate your feedback. Yes, I will be loading one file. Unfortunately, this snippet logs Unhandled Rejection (TypeError): acceptedFiles.item is not a function. I will have to do further debugging. – Aly Hoop Oct 28 '20 at 17:51
  • @AlyHoop I've updated the code snippet. I had incorrectly assumed acceptedFiles was an instance of FileList. https://developer.mozilla.org/en-US/docs/Web/API/FileList – Benjamin Oct 28 '20 at 18:49
  • Well with that revision, it is now logging TypeError: setProductState is not a function again. I will circle back on props. – Aly Hoop Oct 28 '20 at 19:09
  • @AlyHoop I've made one more change to the code snippet, replacing the destructured props, with a props parameter, making it more clear where setProductState is coming from. – Benjamin Oct 28 '20 at 19:43
  • That edit logs TypeError: props.setProductState is not a function. – Aly Hoop Oct 28 '20 at 20:25