You need checked not defaultChecked:
<input type="checkbox" onChange={this.changeF} checked={this.state.checked} />
Also when defining a method/function in a React class-component, you should be cognizant of the this keyword. In the changeF function you defined above, you are trying to update state by using this.setState(). However, if you actually tried to console.log(this) within changeF, you will get undefined, so naturally you cannot use this.setState()
Within changeF we need to point the this keyword to your component somehow, either by using an arrow-function which has lexical-binding, OR by explicitly binding the this keyword belonging to the changeF function inside the component's constructor.
Try turning changeF into an arrow-function, which will implicitly bind the this keyword to your component's execution context:
changeF = () => {
this.setState({ checked: !this.state.checked });
}
See sandbox for working example: https://codesandbox.io/s/prod-http-t480z
Ironically, now that you have a practical answer for your code, you probably now have more questions about this. It is arguably the most confusing topic in JavaScript.
Here's a cheater's guide to understand the this keyword.
Note: this almost always refers to nearest object that is a level above it/owns it.
Let's go through a couple of examples using your console.
Printing this
Code: console.log(this)
Result: Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
There is a global window object, and when you simply print this without any wrapping objects, it points to the nearest one.
Printing this within a function()
Code:
function printSomething(){
console.log(this)
}
printSomething()
Result: Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
Still, this points to the nearest object. The window.
Printing this within a function() that is inside an object
Code:
function nestedThis(){
let myObj = {
getThis: function(){
console.log(this)
}
}
return myObj
}
nestedThis().getThis()
Result: { getThis: ƒ}
Nice! We aren't getting the window object anymore. Instead, now this refers to myObj, which is the object that owns it.
Now to understand why your changeF function did not work:
changeF() {
this.setState({ checked: !this.state.checked });
}
In the context of a React component, the this keyword is not immediately given a value. It will not inherently receive the window object, hence React component's have their own execution scope. And since it cannot find an object at a level above it, in a sense this becomes "lost".
As a workaround, you will see people binding their traditional functions so that the this keyword points to the component context.
constructor(props) {
super(props);
this.state = { checked: true };
this.changeF = this.changeF.bind(this)
}
Note: Within the constructor, the this keyword is defined and you have access to all the class properties.
But why the heck do arrow-functions () => {} work? Well arrow-functions have something called lexical-scoping. Which essentially just means that when you call this inside the function, it will point to the overarching execution context.
this.setState((prevState) => ({ checked: !prevState.checked }) ). Also changeonChange={this.changeF}toonChange={this.changeF.bind(this)}