Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Clicking on switch does not change state the first time only if it's checked already

I’m a newbie in React and just started to develop an admin panel on local to practice what I have learned and I have come across this problem and after searching for a long while and being unable to solve it I’m this close to step on kittens and innocent children …

so here’s the situation:

I have a panel for registering some products, say, Shoes and on my Dashboard page of admin panel I have my products listed and I can click on edit on any of them to redirect to edit page and change the info like name, price, image etc.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Up to this point everything works as intended, the problem is I have a Switch Input which indicates if it’s a featured product or not and when I land on the edit page it displays correctly if it’s On or Off, now when I click on it to change its state, the first time I click nothing happens and it starts working after 2nd click onwards.

I’ve done my research and came to know it has to do with using useEffect() and such and I’ve changed my code accordingly and now the real problem is when the switch is off when I land on edit page, on first click it works just fine and it changes to On and I can save it and it’ll do as intended but if it’s On by default when I land on the edit page, the first click won’t work and it takes 2 click and more to change the state and it escapes me how it works fine when it’s off and not both ways.

p.s it’s my first time asking question here so I might have failed to express my problem clearly or properly enough so my apologies in advance.

Here’s the code:

import {useEffect, useState} from "react";
import {useNavigate, useParams} from "react-router-dom";
import getOneProduct from "../../../Services/getOneProduct";
import {useProductsDispatch} from "../../../Context/productsContext";
import {toast} from "react-toastify";

function EditProductForm() {

    const dispatch = useProductsDispatch()

    const redirect = useNavigate()
    const [product, setProduct] = useState({
        name: '',
        desc: '',
        price: '',
        offPrice: '',
        image: '',
        feat: null,
        uid: '',
        date: '',
    })

    const [switchVal, setSwitchVal] = useState(); // this is the state I use for the switch but would rather have it in the 'product' state above so they are all together

    const switchHandler = (e) => { // the onChange function for the switch
        const curVal = e.target.checked
        setSwitchVal(curVal)
    }

    useEffect(() => { // the useEffect to reflect switch changes
        setProduct({
            ...product,
            feat: switchVal
        })
        console.log(switchVal)
    }, [switchVal, setSwitchVal]);

    const changeHandler = (e) => { // the input handler for all other inputs
        setProduct({
            ...product,
            [e.target.name]: e.target.value,
        })
    }

    const editProductSubmit = (e) => { // form onSubmit
        e.preventDefault()
        dispatch({
            type: 'EDIT_PRODUCT',
            payload: {
                productId,
                product
            }
        })
        redirect("/admin/dashboard")
    }
    const fetchedId = useParams()
    const productId = fetchedId.id
    useEffect(() => {
        const fetchedProduct = async () => {
            try {
                const {data} = await getOneProduct(productId) // axios.get()
                setProduct({
                    name: data.name,
                    desc: data.desc,
                    price: data.price,
                    offPrice: data.offPrice,
                    image: data.image,
                    feat: data.feat,
                    uid: data.uid,
                    date: data.date,
                })
            } catch (error) {
                console.log(error)
            }
        }
        fetchedProduct()
    }, [productId])

    return (
        <div>
            <form className="add-product-form" onSubmit={editProductSubmit}>
                <div className="form-floating mb-3">
                    <input
                        defaultValue={product.name}
                        onChange={changeHandler}
                        type="text"
                        className="form-control"
                        id="productName"
                        name="name"
                        placeholder="نام محصول"
                    />
                    <label className="form-label" htmlFor="productName">نام محصول</label>
                </div>
                <div className="form-floating mb-3">
                    <textarea
                        defaultValue={product.desc}
                        onChange={changeHandler}
                        className="form-control"
                        id="productDesc"
                        name="desc"
                        placeholder="Leave a comment here"
                        style={{height: 200}}
                    />
                    <label htmlFor="productDesc">توضیحات محصول</label>
                </div>
                <div className="form-floating mb-3">
                    <input
                        defaultValue={product.price}
                        onChange={changeHandler}
                        type="number"
                        className="form-control"
                        id="productPrice"
                        name="price"
                        placeholder="قیمت اصلی محصول"
                    />
                    <label className="form-label" htmlFor="productPrice">قیمت اصلی محصول</label>
                </div>
                <div className="form-floating mb-3">
                    <input
                        defaultValue={product.offPrice}
                        onChange={changeHandler}
                        type="number"
                        className="form-control"
                        id="productOffPrice"
                        name="offPrice"
                        placeholder="قیمت با تخفیف محصول"
                    />
                    <label className="form-label" htmlFor="productOffPrice">قیمت با تخفیف محصول</label>
                </div>
                <div className="form-floating mb-3">
                    <input
                        defaultValue={product.image}
                        onChange={changeHandler}
                        type="text"
                        className="form-control"
                        id="productImage"
                        name="image"
                        placeholder="لینک تصویر محصول"
                    />
                    <label className="form-label" htmlFor="productImage">لینک تصویر محصول</label>
                </div>
                <div className="form-check form-switch form-check-reverse mb-3">
                    <input
                        onChange={switchHandler}
                        defaultChecked={product.feat}
                        value={switchVal}
                        type="checkbox"
                        className="form-check-input"
                        id="productFeat"
                        role="switch"
                    /> {/* This is the switch in question */}
                    <label className="form-check-label" htmlFor="productFeat">محصول ویژه است</label>
                </div>
                <div className="mb-3">
                    <button type="submit" className="btn btn-success">ویرایش محصول</button>
                </div>
            </form>
        </div>
    );
}

export default EditProductForm;

>Solution :

I cannot comment (since SO requieres a certain mount of reputation to comment :/), so i cannot answer the question you left on Tim van Dam’s answer directly. But if you want to have a conditional default value for a react components you probably would want to pass that conditional default value as a prop, then use THAT value to initialize your useState()

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading