0

So what i'm trying to do is pass a number to the child component, which will only be passed on the first render. After that i'm trying to change the current value and pass the value from the child, back to the parent component. However i'm not able to pass price to child, as i'm receving undefined.

Not sure how I can pass the data in this context, any ideas?

function Parent(props, {price}) {
        const [amount, setAmount] = React.useState("200");
    
        function handleChange (newValue) {
          setValue(newValue);
        }
    
        // We pass a callback to Child
        return <Child price={amount} value={value} onChange={handleChange} />;
    }
    
    
function Child (props, {price}) {
        const [amount, setAmount] = React.useState("");
            
        function handleChange(event) {
              setAmount(event.target.value)
    
              // Here, we invoke the callback with the new value
              props.onChange(event.target.value);
        }
    
       useEffect(() => {
        setAmount(price) //Pass value from parent if it has one
      }, [])
          
      return <input value={props.value} onChange={handleChange} />
   }
Bob
  • 21
  • 3
  • 14
  • 1
    Make sure to access `price` from `Child` through `props.price` since the second argument to `Child` will be `undefined` – kingkupps May 21 '22 at 21:53

1 Answers1

0

For this usecase, you only need to pass one value from the parent component to its child. You are duplicating values in a way, which is unnecessary and leading to confusion. Either use the amount or value state variable, not both.

To fix this:

  • Use only the amount state variable in both <Parent/> and <Child/>.
  • Change the setValue() call to setAmount() in the handleChange() function.
  • Remove the value prop being passed to <Child/>.
  • Remove the destructured value {price} from <Child/> and access amount in the useEffect() hook instead through the value prop.

Additionally:

  • Don't use props and destructured {propVariable} syntax at the same time in the parameter list of a component. Use either not both.

Parent Component:

function Parent(props) {
    const [amount, setAmount] = useState("200");

    function handleChange(newValue) {
        setAmount(newValue);

        // You can use this to test that the child component is triggering 
        // the handleChange() function prop passed to it.
        console.log(newValue); 
}

    // We pass a callback to Child
    return <Child value={amount} onChange={handleChange} />;
} 

Child Component:

function Child(props) {
    const [amount, setAmount] = useState("");

    function handleChange(event) {
        setAmount(event.target.value);

        // Here, we invoke the callback with the new value
        props.onChange(event.target.value);
    }

    useEffect(() => {
      setAmount(props.value); //Pass value from parent if it has one
    }, []);

  return <input value={props.value} onChange={handleChange} />;
} 

However, even all of the above within <Child/> aren't necessary. You need just the props in the child component, and don't need to maintain internal state in keeping with best practices i.e having a single source of truth and controlling state in parent alone, so you can modify <Child/> further to:

function Child(props) {
    function handleChange(event) {
        // Here, we invoke the callback with the new value
        props.onChange(event.target.value);
    }

    return <input value={props.value} onChange={handleChange} />;
}
Chizaram Igolo
  • 907
  • 8
  • 18
  • 1
    Hmm i see, that is understandable. Although, my example might have been to simplified. As in a bigger user case, this component must handle multiple usecases. But for this example, this looks like the correct answer. – Bob May 22 '22 at 21:57
  • Glad I could help. Even if your component gets more complex, the best solution would be a simple one, but we'll be here to help! – Chizaram Igolo May 22 '22 at 22:58