1

I would like to understand why is it when I'm switching between posts, the input fields are not changing their values, even though each product object has different name and description property.

Further explanation: When clicking on each ProductView (Product Component) a new window is shown with details on that product that could be changed and saved (name and description) through input fields. but when switching between products (by clicking on different products) the text on these input fields do not change.

example product object: product = { name: 'product 1', desc: 'product 1 desc' }

this is the code:

// Main Store Component
const Store = () =>{
    const [prods, setProducts] = useState([...products]);
    const[show, showDetails] = useState(false);
    const[productToShow, setProductToShow]=useState();

    function onSaveProduct(newProduct){
        let i = prods.findIndex((x)=> x['id']===newProduct.id);
        prods[i] = newProduct;
        setProductToShow(newProduct)
        setProducts([...prods]);   
    }

    return(<div className={'flex-container'}>
        <Container className="store-container">
            <div className={'column-align'}>
                {([...prods]).map((pro)=>{
                    return <Product key={pro.id} product={pro} showDetails={showDetails} 
                    setProductToShow={setProductToShow}/>
                })}
            </div>
        </Container>
        {show && <ProductToShow product={productToShow} onSave={onSaveProduct}/>}
        
    </div>);
}

// Product component
const Product = ({product, setProductToShow, showDetails, deleteFromList}) =>{
    const handleClick = () =>{
        setProductToShow(product);
        showDetails(true);
    }
    return (
        <div className="product-container">
            <div className="name-desc"onClick={handleClick}>
                <h3>{product.name} </h3>
                <h5>{product.desc}</h5>
            </div>
        </div>
    );
}

// ProductToShow functional component
const ProductToShow = ({product, onSave}) =>{
    const nameInput = useFormInput(product.name); 
    const descInput = useFormInput(product.desc); 

    const newProduct = {
        id: product.id,
        name: nameInput.value,
        desc: descInput.value,
    };

    function useFormInput(initialValue){
        const[value, setValue] = useState(initialValue);

        function handleChangeEvent(e){
            setValue(e.target.value);
        }
        return{
            value: value,
            onChange: handleChangeEvent
        }
    }
    
    return (
        <div className="to-show-container">           
            <h1>{product.name}</h1>
            <label>Product Name: </label>
            <input {...nameInput}/>
            <label>Product Description: </label>
            <input {...descInput}/>
            <div className={'to-the-right'}>
                <Button onClick={()=>onSave(newProduct)}>Save</Button>
            </div>
        </div>
    );
}

screenshot (Product 3 is clicked, but the details of Product 1 is shown in the input fields):

enter image description here

2 Answers 2

1

The problem is in your productToShow functional component. The values don't get reupdated after clicking on a different product.

Maybe consider changing it to something like this:

// ProductToShow functional component
const ProductToShow = ({ product, onSave }) => {
  const [name, setName] = useState(product.name);
  const [desc, setDesc] = useState(product.desc);

  useEffect(() => {
    setName(product.name);
    setDesc(product.desc);
  }, [product]);

  return (
    <div className="to-show-container">
      <h1>{product.name}</h1>
      <label>Product Name: </label>
      <input value={name} onChange={(e) => setName(e.target.value)} />
      <label>Product Description: </label>
      <input value={desc} onChange={(e) => setDesc(e.target.value)} />
      <div className={"to-the-right"}>
        <Button
          onClick={() => onSave({id:product.id,name,desc})}>
          Save
        </Button>
      </div>
    </div>
  );
};

I used useState since I don't know if you want to use it further in that component or not. If the only purpose of the component is to update the products, I would take the advice of the other answer and wrap the inputs in a form tag and take the inputs after submitting the form

Sign up to request clarification or add additional context in comments.

1 Comment

I was trying to useFormInput as a custom hook that will handle all the input fields, but it seems that i do need the useEffect hook to change the name and desc fields each time we select a different product. i know this way to go about it works, but i was trying to understand why it doesn't work with useFormInput custom hook.
1

It could be problem with reinitialization of inputs.

ProductToShow component is the same for any selected product. You pass props (they could be changed) but I'm not sure if nameInput is changed here after product props changes:

const nameInput = useFormInput(product.name);

I think it's better to wrap inputs with the <form>...</form> and control reinitialization with initialValues.

also:

  • would be helpful to have codesandbox or something.
  • not need to use [...spread] if spead is array[].
  • not need to have to states for show / not-to-show & productToShow. Just use productToShow with null option when you don't want to show any product.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.