Home > other >  How to update state shared between Parent and Child React components within the Parent
How to update state shared between Parent and Child React components within the Parent

Time:12-04

I've built a simple interface for selecting items from a menu, contained in a component called Sodas, and it's displayed in the Parent component: VendingMachine.

As it is, Sodas is able to successfully change the state in the VendingMachine, however, the state cannot be changed within the VendingMachine itself.

The following code represents the VendingMachine component:

import Sodas from './Sodas';

const VendingMachine = () =>
{
   // Track selected soda
   const [selectedSoda, setSoda] = useState({ sodaName: '', stock: 0 });

   const handleSodaSelection = (soda) => setSoda(soda);

   // Reset the selected soda
   const sellSoda = () => setSoda({ sodaName: '', stock: 0 });

   return (
   <div>
      Soda to Purchase: {selectedSoda.sodaName}
      <Sodas handleSodaSelection={handleSodaSelection} />
      <div onClick={sellSoda}>Buy Selected Soda</div>
   </div
}

The following code represents the Sodas Component

function Sodas({ handleSodaSelection  })
{
   // Tracks soda selected, and returns to Parent component
    const [sodaSelected, setSodaSelected] = useState({ sodaName: '', stock: 0 });
    React.useEffect(() => handleSodaSelection(sodaSelected), [sodaSelected, handleSodaSelection]);

return (
   <div className='soda_container'>
      <div onClick={() => setSodaSelected({ sodaName: 'Cola', stock: 7 })}>Soda</div>
   </div>)
}

Specifically, the issue is that setSoda does not work within VendingMachine and only works when passed to the Sodas component. I'm not sure if this can only work as a one way relationship or if there is something I'm missing in the syntax.

Any help or references to relevant documentation would be greatly appreciated.

CodePudding user response:

You should pass the state and the function to update the state from the parent component, VendingMachine, to the child component, Sodas, as props. Then, the child component, Sodas, can use the function passed as a prop to update the state in the parent component.

VendingMachine component:

import Sodas from './Sodas';

const VendingMachine = () => {
// Track selected soda
const [selectedSoda, setSoda] = useState({ sodaName: '', stock: 0 });

// Reset the selected soda
const sellSoda = () => setSoda({ sodaName: '', stock: 0 });

return (
<div>
Soda to Purchase: {selectedSoda.sodaName}
<Sodas selectedSoda={selectedSoda} setSoda={setSoda} />
<div onClick={sellSoda}>Buy Selected Soda</div>
</div>
);
}

Sodas component:

function Sodas({ selectedSoda, setSoda }) {
return (
<div className='soda_container'>
<div onClick={() => setSoda({ sodaName: 'Cola', stock: 7 })}>Soda</div>
</div>
);
}

the VendingMachine component passes the selectedSoda state and the setSoda function to the Sodas component as props. The Sodas component then uses the setSoda function passed as a prop to update the selectedSoda state in the VendingMachine component.

CodePudding user response:

In the code you provided, the setSoda function is only passed to the Sodas component as the handleSodaSelection prop. This means that setSoda can only be called within the Sodas component. If you want to be able to call setSoda in the VendingMachine component as well, you can pass it to the Sodas component as a prop.

Here is how you could modify the Sodas component to accept the setSoda function as a prop and pass it down to any child components that need to be able to update the selectedSoda state:

function Sodas({ handleSodaSelection, setSoda  })
{
   // Tracks soda selected, and returns to Parent component
    const [sodaSelected, setSodaSelected] = useState({ sodaName: '', stock: 0 });
    React.useEffect(() => handleSodaSelection(sodaSelected), [sodaSelected, handleSodaSelection]);

    // Pass setSoda down to any child components that need to be able to update the selectedSoda state
    const handleSodaSelection = (soda) => setSoda(soda);

return (
   <div className='soda_container'>
      <div onClick={() => setSodaSelected({ sodaName: 'Cola', stock: 7 })}>Soda</div>
   </div>)
}

Then, in the VendingMachine component, you can pass the setSoda function to the Sodas component as a prop:


const VendingMachine = () =>
{
   // Track selected soda
   const [selectedSoda, setSoda] = useState({ sodaName: '', stock: 0 });

   // Reset the selected soda
   const sellSoda = () => setSoda({ sodaName: '', stock: 0 });

   return (
   <div>
      Soda to Purchase: {selectedSoda.sodaName}
      <Sodas handleSodaSelection={handleSodaSelection} setSoda={setSoda} />
      <div onClick={sellSoda}>Buy Selected Soda</div>
   </div
}

This way, both the Sodas component and the VendingMachine component will be able to call the setSoda function to update the selectedSoda state.

  • Related