Can I setState in Parent from Child component?

I would like to clean my code a bit so instead of having one long component I would like to create child component.

In my Parent I have some states I would like to update onClick in Child.

Parent:

const [plan, setPlan] = useState('myPlan');
const [months, setMonths] = useState('2');
const [price, setPrice] = useState(200);

<PlanSelection props={props}
               item={selectedData}
               itemPlan={plan}
 />

Child

const PlanSelection = ({ props, item, itemPlan }) => {

    function handleSubsribe() {
        props.setPlan('Subsribe Only');
        props.setPrice(item.price);
        props.setMonths('24+');
    }

    function handlePay() {
        props.setPlan('Pay to Own');
        props.setPrice(item.pay);
        props.setMonths('12-24');
    }

And just trying to call the functions (in Child component)

<button onClick={handleSubscribe} />
<button onClick={handlePay} />

Using the code above throws error after clicking in one of the buttons:

TypeError: props.setPlan is not a function

But if I don’t pass props, setPlan, setPrice, …. will be undefined. Is there a way how to handle it ?

Answer

Problem

<PlanSelection props={props}
               item={selectedData}
               itemPlan={plan}
 />

You did not pass setPlan to child, you have only passed props, which props has nothing to do with state, selectedData which I’m not sure what’s that, and plan, which is the state. In summary you did not pass anything about setState to child component


Solution

Parent

const [plan, setPlan] = useState('myPlan');

<PlanSelection 
  setPlan={setPlan}
 />

Child

const PlanSelection = ({ setPlan }) => {

    function handleSubsribe() {
        setPlan('Subsribe Only');
    }

    function handlePay() {
        setPlan('Pay to Own');
    }

In the code above I’ve only used setPlan as an example to show you how to setState from child component, you can apply same logic to the rest.

UPDATES Just realized I’ve made a mistake which you should be worth noting. In your child component you have ({ setPlan }), this is known as destructuring, which is you are extracting setPlan out of props, hence in your child component, you should not be accessing props.setPlan but setPlan instead. Do take a look at the answer above again