Search code examples
reactjsformsreact-hookscomponents

Get component value from child component in React


I have created drop down/lookup components for a form, each stored as a separate file under a components folder. At the moment the list of items in each component is fed from an array within the component for testing and with the idea it will eventually come from an API call. I have each component coded to update using state when the user selects an option from the drop down. I then created a form, imported the child components and added a submit button. Where I am struggling is getting the value of the list boxes to use with the submit button. I am thinking I need to use state but my understanding of React (still very very new, this is my first project) is that state flows from parent to child not the reverse. I have included my form and one of the child components. Could someone show/explain to me what I need to do?

Parent:

`import "bootswatch/dist/sandstone/bootstrap.css";
import SelectGrowers from "./Components/SelectGrowers";
import SelectStacks from "./Components/SelectStacks";
import SelectCustomers from "./Components/SelectCustomers";
import SelectCarriers from "./Components/SelectCarriers";

function AddPOForm() {
  return (
    <>
      <form className="form-group">
        <div className="container">
          <div className="row">
            <div id="growers" className="col-sm-4">
              <SelectGrowers />
            </div>

            <div className="col-sm-4">
              <SelectStacks />
            </div>
          </div>


          <div className="row">
            <div className="col-sm-4">
              <SelectCustomers />
            </div>

            <div className="col-sm-4">
              <SelectCarriers />
            </div>
          </div>
        </div>
        <input type="Submit" />
      </form>
    </>
  );
}

export default AddPOForm;`

** Child component:**

`import React, { useState } from "react";

interface Props {
  onSelectItem: (item: string) => void;
}

export default function SelectGrowers() {
  let growers = [
    { id: 1, value: "Grower A" },
    { id: 2, value: "Grower B" },
    { id: 3, value: "Grower C" },
  ];
  let [grower, setGrower] = useState();

  let handlGrowerChange = () => {
    setGrower(grower);
  };

  return (
    <div className="form-group">
      <label htmlFor="growerList" className="form-label mt-4">
        Grower
      </label>
      <select
        onChange={() => handlGrowerChange}
        name="growerList"
        className="form-select"
      >
        <option>Please Select a Grower</option>
        {growers.map((grower) => (
          <option key={grower.id}>
            {grower.id} - {grower.value}
          </option>
        ))}
      </select>
    </div>
  );
}`

Solution

  • You're on the right track. However if you're planning on using the data from the Parent component, that's where you need to keep your state. So move this line let [grower, setGrower] = useState(); to the parent file. Now use the call back you're passing to your child component to update the state in the parent component whatever a new value is selected.

    Parent component:

    let [grower, setGrower] = useState();
    
    let handlGrowerChange = (grower) => {
      setGrower(grower);
    };
    
    ... 
    
    <SelectGrowers onSelectItem={handleGrowerChange} />
    

    Eventually if you need the select to be controlled, you can pass in the state value to your child component too.