52

I'm creating my first application with ReactJS and I found this warning when I run my code :

Warning: Failed form propType: You provided a checked prop to a form field without an onChange handler. This will render a read-only field. If the field should be mutable use defaultChecked. Otherwise, set either onChange or readOnly. Check the render method of Login.

Can someone tell me how I fix it please ?

JSK NS
  • 3,346
  • 2
  • 25
  • 42
Randa
  • 669
  • 2
  • 7
  • 8

6 Answers6

61

React has 2 ways of working with form controls - Controlled Components and Uncontrolled Components

You get this warning when you don't supply the element neither the attributes needed for controlled nor those needed for an uncontrolled component:

Warning: Failed form propType: You provided a checked prop to a form field without an onChange handler. This will render a read-only field. If the field should be mutable use defaultChecked. Otherwise, set either onChange or readOnly. Check the render method of Login.

Controlled Components


Attributes needed:

  1. value - <input> (not checkbox or radio), <select>, <textbox> or checked for (checkbox or radio).
  2. onChange

React handles the condition of the element by updating the value or checked attribute (depending on the element) from the props or the state. We need to notify react when we make a change, like inserting data, or checking the box, so react can update the element's condition when it rerenders the component. To do so, we must include an onChange handler, in which we will update the state or notify the component's parent, so it will update the props.

<input
  type="checkbox"
  checked={ this.props.checked }
  onChange={ this.checkboxHandler } 
/>

const { render } = ReactDOM;

class Demo extends React.Component {
  constructor(props) {
    super(props);
    
    this.state = {
      checked: true
    };
    
    this.checkboxHandler = this.checkboxHandler.bind(this);
  }
  
  checkboxHandler(e) {
    this.setState({
      checked: e.target.checked
    });
  }
  
  render() {
    return (
      <input
        type="checkbox"
        checked={ this.state.checked }
        onChange={ this.checkboxHandler } 
      />
    );
  }
}

render(
  <Demo />,
  document.getElementById('demo')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.1/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.1/react-dom.js"></script>

<h1>The Checkbox</h1>

<div id="demo"></div>

Uncontrolled Components


Attributes needed:

defaultValue - <input> (not checkbox or radio), <select>, <textbox> or defaultChecked for (checkbox or radio).


React sets the initial value using defaultValue or defaultChecked, and the update of the element's state is controlled by the user, usually via the DOM using refs.

<input
  type="checkbox"
  defaultChecked={ this.props.checked } 
/>
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
48

The defaultChecked may not be updated if the component is re-rendered in future so use this approach with caution.

You may be better off just using a blank function to remove the warning. Especially if you want to handle click on the whole div which includes the checkbox and the associated text.

<div onClick={this.handleClick}>
  <input type="checkbox" checked={this.props.checked} onChange={()=>{}}/>
  {this.props.text}
</div>
Piotr Berebecki
  • 7,428
  • 4
  • 33
  • 42
  • 4
    This is exactly what I was looking for. I'm afraid that this warning encourages bad programming practices. To put a new handler on every single checkbox you render will cause the browser to use more memory than to have the handler on the surrounding element of all the checkboxes that need to be handled. – Bobort Mar 27 '19 at 21:43
  • You shouldn't need to resort to this because ordinarily `this.handleClick` could be called with the `onChange` handler. If you are unable to do this, perhaps you should consider restructuring the HTML slightly, for example through the use of ` – Kevin Farrugia Jan 09 '20 at 13:29
  • @KevinFarrugia Care to elaborate? If the outer `div` spans the entire width of the viewport; how would restructuring the DOM through a label help you achieve the same functionality without having to resort to the hack of providing an empty function? – Kevin Johnson Jan 03 '21 at 13:39
  • @KevinJohnson You shouldn't need to have a click handler on the `div`. https://codepen.io/kevinfarrugia/pen/OJRvGNm – Kevin Farrugia Jan 04 '21 at 10:26
46

You need to add defaultChecked attribute to your checkbox:

<div>
    <input type='checkbox' defaultChecked />
</div>
t1m0n
  • 3,413
  • 1
  • 17
  • 21
3

For those that prefer a Functional Component instead of a Class Component this Controlled Component approach is simple and easy to implement. If you don't know what a Controlled Component is then please refer to @Ori Drori's well explained answer in this thread.

import {useState} from "react";

export default function YourComponentName(){

  const [checked, setChecked] = useState(true);

  return (
    <>
          <input
            type="checkbox"
            checked={checked}
            onChange={() => setChecked(!checked)}
          />
    </>
  );
};
Aaron Miller
  • 185
  • 11
1

For those who are using react material ui and react-hook-form. the proper way to create a controlled checkbox is

import { useForm, Controller } from "react-hook-form";
import {
  Checkbox,
  FormControlLabel,
} from "@mui/material";

const { handleSubmit, control } = useForm()
...

<Controller
  control={control}
  name={`${item.id}`}
  defaultValue={!!evaluationDimensions?.[item.id]?.selected} 
  render={({ field: { onChange, value } }) => (
    <FormControlLabel
      control={
        <Checkbox
          checked={value}
          onChange={onChange}
        />
      }
    />
  )}
/>
...

Make sure to defaultValue whenever you use checked={value} to prevent issues such

React warning MUI: A component is changing the default checked state of an uncontrolled SwitchBase after being initialized
DINA TAKLIT
  • 7,074
  • 10
  • 69
  • 74
0

If your confronting with this warning, You can add "readOnly" to your input. like this code:

<div>
    <input type='checkbox' checked={ props.checkBoxChecked } readOnly />
</div>

Or You can add an onChange event like an empty arrow function or what kind of function you care about to your input. like this:

<div>
    <input type='checkbox' checked={ props.checkBoxChecked } onChange={() => {}} />
</div>

Also you must care about the value property, too. This solution fixed my issue with the same warning, hope to be useful.

Pouria
  • 1
  • 2