Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React <Switch> is not getting updated or changing its state

Hey guys I am learning react and have a form to edit book details. I am using django in the backend. I am not able to update the e-book which is a switch to turn on and off according to whether e-book is available or not. The switch works fine, but no data is being changed in the database. I am confused on how to work with the switch and saw lots of resources saying different things which is quite difficult to understand. Rest of the fields are getting updated correctly. Can someone tell me what changes I have to make in this switch to make it work??

code

import React, {useEffect, useState} from 'react'
import axiosInstance from '../../axios';
import { useForm, Controller } from 'react-hook-form';

//MaterialUI
import Button from '@material-ui/core/Button';
import CssBaseline from '@material-ui/core/CssBaseline';
import TextField from '@material-ui/core/TextField';
import Grid from '@material-ui/core/Grid';
import Typography from '@material-ui/core/Typography';
import { makeStyles } from '@material-ui/core/styles';
import Container from '@material-ui/core/Container';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import Switch from '@material-ui/core/Switch';
import Select from '@material-ui/core/Select';
import InputLabel from '@material-ui/core/InputLabel';
import MenuItem from '@material-ui/core/MenuItem';
import FormControl from '@material-ui/core/FormControl';


const useStyles = makeStyles((theme) => ({
    paper: {
        marginTop: theme.spacing(8),
        display: 'flex',
        flexDirection: 'column',
        alignItems: 'center',
    },
    bookformbody: {
        display: "flex",
        backgroundColor: "#ffff",
        height: "100vh",
    },
    form: {
        width: '100%', // Fix IE 11 issue.
        marginTop: theme.spacing(3),
    },
    submit: {
        margin: theme.spacing(3, 0, 2),
    },
}));


function BookEdit() {    
    const initialFormData = Object.freeze({
        id: '',
        summary: '',
        published_date: '',
        e_book: false,
    });

    const [formData, updateFormData] = useState(initialFormData);

    useEffect(() => {
        axiosInstance.get('api/books/details/view/').then((res) => {
            updateFormData({
                ...formData,
                ['summary']: res.data.summary,
                ['published_date']: res.data.published_date,
                                ['e_book']: res.data.e_book,

            });
            console.log(res.data);
        });
    }, [updateFormData]);

    const handleChange = (e) => {
        if(e.target.name === "e_book"){
             return(
                 updateFormData({
                     ...formData,
                     [e.target.name]: e.target.checked
                 })
                
             )
        }   
        updateFormData({
            ...formData,         
            // Trimming any whitespace
            [e.target.name]: e.target.value
        });
    };


    const onSubmit = (data) =>{
        let formData = new FormData();

        formData.append('summary', data.summary);
        formData.append('published_date', data.published_date);
        formData.append('e_book', data.e_book);

        axiosInstance.put('api/books/details/edit/', formData);

    } ;
    
    const classes = useStyles();
    const { register, handleSubmit, control, errors } = useForm();

    return (
        <>
            <Header />
            <div className={classes.bookformbody}>
                <SideBar />
                <Container component="main" maxWidth="sm">
                    <CssBaseline />
                    <div className={classes.paper}>
                        <Typography component="h1" variant="h5">
                            Edit Book Details
                        </Typography>
                        <form className={classes.form} noValidate onSubmit={handleSubmit(onSubmit)}>
                            <Grid container spacing={2}>
                                <Grid item xs={12}>
                                    <TextField
                                        variant="outlined"
                                        required
                                        fullWidth
                                        id="summary"
                                        label="Book Summary"
                                        name="summary"
                                        autoComplete="summary"
                                        value={formData.summary}
                                        onChange={handleChange}
                                        inputRef={register({maxLength: 1000})}
                                        multiline
                                        rows={4}
                                    />
                                </Grid>

                                <Grid item xs={12}>
                                    <TextField
                                        variant="outlined"
                                        required
                                        fullWidth
                                        type="date"
                                        label="Published Date"
                                        name="published_date"
                                        autoComplete="published_date"
                                        value={formData.published_date}
                                        onChange={handleChange}
                                        inputRef={register({required: true})}
                                        InputLabelProps={{
                                            shrink: true,
                                          }}
                                    />
                                </Grid>

                                <Grid item xs={12}>
                                    <InputLabel id="e-book-switch">E-Book</InputLabel>
                                        <Controller
                                            name="e_book"
                                            control={control}
                                            as={
                                                <Switch size="small"
                                                    id="e-book-switch" 
                                                    type="checkbox"
                                                    name="e_book"
                                                    onChange={handleChange} 
                                                    // inputRef={register}
                                                    value={formData.e_book}
                                                    checked={formData.e_book}
                                                />
                                            }
                                        />
                                </Grid>
                            </Grid>
                            <Button
                                type="submit"
                                fullWidth
                                variant="contained"
                                color="primary"
                                className={classes.submit}
                            >
                                Update
                            </Button>
                        </form>
                    </div>
                </Container>
            </div>
        </>
    )
}

export default BookEdit;
like image 460
prehistoricbeast Avatar asked Nov 05 '25 14:11

prehistoricbeast


2 Answers

You are passing props to Switch directly, but what you should do is to use Controller props, and Controller will then pass it down to Switch:

<Controller as={Switch} value={formData.e_book} ... />

Otherwise you need to use render, not as This is actually described pretty good here: https://react-hook-form.com/api/#Controller


UPDATE

Here is the sandbox where it is working fine with above changes - https://codesandbox.io/s/kind-nash-s94v0

What i did there is simply this:

  <Controller
  name="e_book"
  control={control}
  render={(props) => {
   return (
     <Switch
      size="small"
      id="e-book-switch"
      type="checkbox"
      name="e_book"
      onChange={handleChange}
      // inputRef={register}
      value={formData.e_book}
      checked={formData.e_book}
    />
   );
}}

/>

like image 187
Nikita Chayka Avatar answered Nov 08 '25 03:11

Nikita Chayka


You are initializing the value as a string at the beginning of BookEdit(). Try to set initialFormData like this:

const initialFormData = Object.freeze({
        id: '',
        summary: '',
        published_date: '',
        e_book: false,
    });
like image 30
genechk Avatar answered Nov 08 '25 03:11

genechk