1

I am having trouble making a checkbox react to its onChange event(checkbox remains in its default state). I have seen similar post here, but nothing really seems to work. I'm hoping a different set of eyes could help figure out whats wrong with my logic.

Here is the handleChange function, and the initial values of the input fields which are both in the parent component

const [accountData, setAccountData]=useState({accountType:'Free',  //default input value for text input
                                              accountStatus: false }) //default input for checkbox input

const handleSubmit={/*submitLogic*/}       

const handleChange = e =>{
         
const target = e.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
setAccountData({...accountData, [name]:value})
}

//passing the handle change as a prop to the EditView component\\
<EditView  handleChange={handleChange} handleSubmit={handleSubmit} data={accountData}/>

Here is the child component that contains the input form(Concern is the checkbox, as the text input field reacts to its onChange event).

const EditView = ({ handleChange, handleSubmit, data}) =>{
    
const isChecked=data.accountStatus;

<form onSubmit={handleSubmit}>
        <div className="form-row" >
                    <div className="form-group col-md-6">
                     < label htmlFor="accountType">Account Type:</label>
                       <input 
                           type="text"
                           className="form-control" 
                           id="accountType"
                           name="accountType"
                           value={data.accountType}
                            onChange={handleChange}/>
                           
                  </div>
                  <div className="form-group col-md-6">
                      < label htmlFor="accountStatus">Account Status:</label>
                      <div className="custom-control custom-switch">
                        <input 
                            type="checkbox"
                            className="custom-control-input "
                             id="accountStatus"
                             name='accountStatus'
                            checked={isChecked}
                            //value={isChecked}
                            onChange={handleChange}
                            
                            />
                  </div>
             </div>
       <button type='submit' >Submit</button>

</form>
}

I even tried creating a different onChange handle function, but still had the same problem. Have I done something wrong in the above code that makes my checkbox not change from its default state?

1
  • Not part of your question but elements with a space before the element name like < label htmlFor will not render properly Commented Aug 23, 2020 at 12:54

2 Answers 2

1

try this onChange={event => handleChange(event)}

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

Comments

0

The value passed to useState is the initial value of the state. If you want to use a values passed down through the properties, without managing it in the component itself don't use state.

const EditView = ({handleChange, handleSubmit, data}) => {
  const isChecked = data.accountStatus;

  // ...
};

When you use:

const [isChecked, setIsChecked] = useState(data.accountStatus);

You are saying, I want to manage isChecked in this component, but the initial value is set to data.accountStatus. For this reason changing data.accountStatus later on won't effect the value of isChecked, since that can only be changed with the setIsChecked function.


The reason the checkbox doesn't work after the edit you made to the question is due to the use of Bootstrap. When you use custom form elements Bootstrap will replace the actual input element, with some visual representation (styled element). This means that when you click on the Bootstrap checkbox/switch you aren't actually clicking on the input.

To solve this issue I'd recommend using React Bootstrap which integrates Bootstrap into React. Here is a working example (click the "full page" button after running the snippet to prevent overlapping of the console output with the content):

const {useState} = React;
const {render} = ReactDOM;
const {Form} = ReactBootstrap;

function App() {
  const [accountData, setAccountData] = useState({
    accountType: "Free",
    accountStatus: false,
  });
  
  const handleChange = ({target}) => {
    const name  = target.name;
    const value = target.type == "checkbox" ? target.checked : target.value;
    setAccountData({...accountData, [name]: value});
  };
  
  console.log(accountData);
  return <EditView data={accountData} onChange={handleChange} />;
}

function EditView({data, onChange}) {
  return (
    <Form>
      <Form.Group>
        <Form.Label>Account Type:</Form.Label>
        <Form.Control
          id="accountType"
          name="accountType"
          type="text"
          value={data.accountType}
          onChange={onChange}
        />
      </Form.Group>
      <Form.Group>
        <Form.Label>Account Status:</Form.Label>
        <Form.Switch
          id="accountStatus"
          name="accountStatus"
          label=""
          checked={data.accountStatus}
          onChange={onChange}
        />
      </Form.Group>
    </Form>
  );
}

render(<App />, document.getElementById("root"));
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" />
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/react/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/react-bootstrap@next/dist/react-bootstrap.min.js"></script>
<div id="root"></div>

4 Comments

That was an important info thank you. However, after following your correction, I still have problem with the onChange. The thing is that the Input text reacts to onChange while the check box does not, even if they have the same handleChange function. Any Ideas why this could be happening?
@Usman This is due to react replacing hiding your checkbox and replacing it with a representation of the checkbox. I've updated my answer with a solution.
I have used the React Bootstrap, when I use the Form.Switch nothing appears (I expect a toggle switch), but when I use the Form.Check, a normal checkbox appears and it reacts to onChange. However, I noticed clicking on the blank space where the toggle switch is supposed to appear causes my isChecked state to change. The toggle switch is not visible, but works. Any advice?
@Usman I've noticed that as well, you have to provide a label for it it show properly. In my example snippet I simply pass an empty string as the label. When removing that property the switch doesn't show.

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.