Keremcan Buyuktaskin
Keremcan Buyuktaskin

Reputation: 327

Passing state from child to parent using hooks - React

Basically, I want to pass the "filename" state from child component to the parent component. So that, I can use the "filename" state in the onSubmit function at parent. How can I achieve that? Currently filename at parent is not defined. Thanks a lot for your help.

Parent:

const AddLocation = ({ addLocation }) => {
  const initialFormState = { title: '', thumbnail: '' };
  const [location, setLocation] = useState(initialFormState);

  const onChange = (e) => {
    setLocation({ ...location, [e.target.name]: e.target.value });
  };

  const onSubmit = () => {
    addLocation({
      ...location,
      thumbnail: filename // I want to use filename state from child here.
    });
  };

  return (
        <form onSubmit={onSubmit}>
          <TextInput
            id="add-loc-title"
            name="title"
            value={location.title}
            onChange={onChange}
          />
          <FileUpload />
          <Button type="submit">Submit</Button>
        </form>
  );
};

Child:

const FileUpload = () => {
  const [file, setFile] = useState('');
  const [filename, setFilename] = useState('Choose File');

  const onChange = (e) => {
    setFile(e.target.files[0]);
    setFilename(e.target.files[0].name);
  };

  const onSubmit = async () => {
    const formData = new FormData();
    formData.append('file', file);
    await axios.post('/upload', formData, {
      headers: {
        'Content-Type': 'multipart/form-data'
      }
    });
  };

  return (
      <form onSubmit={onSubmit}>
        <TextInput
          id="add-cat-thumb"
          name="thumbnail"
          type="file"
          onChange={onChange}
      </form>
    </>
  );
};

Upvotes: 1

Views: 91

Answers (2)

SomoKRoceS
SomoKRoceS

Reputation: 3043

You should handle a state at Parent and pass the setState to the Child. Then call it on event.

Parent:

  const [file, setFile] = useState(''); // create a state as the parent

  const onSubmit = () => {
    addItem({
      ...item,
      file: filename
    });
  };
    
  return <FileUpload parentSetFile={setFile}/>

Then use parentSetFile in Child:

  const onChange = (e) => {
    props.parentSetFile(e.target.files[0]) // For Example
    setFile(e.target.files[0]);
    setFilename(e.target.files[0].name);
  };

Edit after full code posted:

So I assume you want the file will be updated in the parent after the submit succeeded, then you should do something like that:

Parent:

const AddLocation = ({ addLocation }) => {
  const initialFormState = { title: '', thumbnail: '' };
  const [location, setLocation] = useState(initialFormState);
  const [submittedFileName, setSubmittedFileName] = useState(null); // New state here to save the submitted file from child.

  const onChange = (e) => {
    setLocation({ ...location, [e.target.name]: e.target.value });
  };

  const onSubmit = () => {
    addLocation({
      ...location,
      thumbnail: submittedFileName  // Use the submitted file name - a state handled in this component (Parent)
    });
  };

  return (
        <form onSubmit={onSubmit}>
          <TextInput
            id="add-loc-title"
            name="title"
            value={location.title}
            onChange={onChange}
          />
          <FileUpload updateFileNameToParent={setSubmittedFileName} /> // Pass teh function that sets submittedFileName to the child so he could use it anyware he wants (probably after submit).
          <Button type="submit">Submit</Button>
        </form>
  );
};

Child:

const FileUpload = (props) => {  // Since this component now gets props, we should pass it here
  const [file, setFile] = useState('');
  const [filename, setFilename] = useState('Choose File');

  const onChange = (e) => {
    setFile(e.target.files[0]);
    setFilename(e.target.files[0].name);
  };

  const onSubmit = async () => {
    const formData = new FormData();
    formData.append('file', file);
    await axios.post('/upload', formData, {
      headers: {
        'Content-Type': 'multipart/form-data'
      }
    });
    props.updateFileNameToParent(filename) // Call the function that sets submitedFileName for parent with the filename in the state of this component (Child)
  };

  return (
      <form onSubmit={onSubmit}>
        <TextInput
          id="add-cat-thumb"
          name="thumbnail"
          type="file"
          onChange={onChange}
      </form>
    </>
  );
};

Upvotes: 1

Jose Cabrera Zuniga
Jose Cabrera Zuniga

Reputation: 2619

The basic idea is like this: Let's suppose you have a react component called < Parent > with state variable fileName. Let's suppose you need to run another react component called < TheChild > from the Parent's render function. Then, to use the Parent's medthods, functions, state vars, etc. at TheChild you could pass the reference of the parent to the child as with:

   return( 
              ...
             <TheChild calledMe={this} />
              ...
   )

this will allow you to use this.props.calledMe within TheChild's code to update the state of the Parent component as with:

this.props.calledMe.setState({fileName: .......}, () => {maybe do something else with fileName state variable})

Upvotes: 1

Related Questions