Class components were widely used before the introduction of hooks (with React 16.8, in February 2019)
Today focus is shifting away from class components and towards hooks
reasons for using hooks:
this
reasons for using class components:
import { Component } from 'react';
class App extends Component {
constructor(props) {
// ...
this.state = { name: 'World' };
}
render() {
return <div>Hello, {this.state.name}!</div>;
}
}
export default App;
Props can be accessed via this.props
:
type TodoItemProps = {
todo: Todo;
onDelete: (id: number) => void;
};
class TodoItem extends Component<TodoItemProps> {
render() {
return (
<li>
{this.props.todo.completed ? 'DONE: ' : 'TODO: '}
{this.props.todo.title}
</li>
);
}
}
In class components, this.state
represents the state.
this.state
is always a JavaScript object which can have various entries (properties)
State changes happen via this.setState()
this.state is always an object:
{
"todos": [],
"loadingStatus": "idle"
}
type TodoAppProps = {};
type TodoAppState = {
todo: Array<Todo>;
loadingStatus: string;
};
class TodoApp extends Component<
TodoAppProps,
TodoAppState
> {
// ...
}
The state must be initialized in the constructor
The constructor will also receive the component's props as an argument
constructor(props: TodoAppProps) {
super(props);
this.state = {
todos: [],
loadingStatus: "idle",
}
}
JavaScript requires calling the constructor of the parent class (Component
) via super()
in the constructor
this.setState({ loadingStatus: 'loading' });
setState
will change all specified entries and leave the rest unchanged
in class components - especially in event handlers - this
may sometimes be set incorrectly
generic problem: method calls without method syntax:
class Foo {
constructor() {
this.message = 'hello';
}
greet() {
console.log(this.message);
}
}
const foo = new Foo();
foo.greet(); // ok
const greet = foo.greet;
greet(); // not ok ("this" is undefined)
problem inside React renderings:
class Foo extends Component {
// ...
greet() {
console.log(this.message);
}
render() {
return <button onClick={this.greet}>hello</button>;
}
}
solution A: arrow methods:
class Foo extends Component {
// ...
greet = () => {
console.log(this.message);
};
// ...
}
solution B: binding the method in the constructor:
constructor() {
// ...
this.greet = this.greet.bind(this);
}
convert existing components (e.g. AddTodo
) from function components to class components