eolas/neuron/cd5cdd66-905b-4f1f-b8e8-3a11ad507325/Comparing_React_classes_to_hooks.md

153 lines
4.5 KiB
Markdown
Raw Normal View History

2024-12-09 18:34:15 +00:00
---
tags:
- javascript
- react
---
# Comparing class components to hook-based components
We will look at the same component written with hooks and classes. Both use this
child component:
```jsx
const CounterBox = (props) => {
return <div className="output">{props.counterValue}</div>;
};
```
## Class component
```jsx
import CounterBox from "./CounterBox";
class CounterClass extends React.Component {
constructor(props) {
super(props);
this.state = {
counterValue: 0,
};
}
addOne() {
this.setState({
counterValue: this.state.counterValue + 1,
});
}
render() {
return (
<React.Fragment>
<button onClick={() => this.addOne()}>Add One</button>
<CounterBox counterValue={this.state.counterValue} />
</React.Fragment>
);
}
}
```
## Hook version
```jsx
import React, { useState } from "react";
import CounterBox from "./CounterBox";
function CounterHook() {
const [counter, setCounter] = useState(0);
const handleClick = () => setCounter(counter + 1);
return (
<React.Fragment>
<button onClick={handleClick}>Add One</button>
<CounterBox counterValue={counter}></CounterBox>
</React.Fragment>
);
}
```
## Main differences
- Obviously with hooks we use a function, not a class. We can therefore think of
them as **simple components** that are able to handle state as well as props.
- We have written the hook as a declared function but we could just as easily
write it as a function expression or arrow function.
- With the class, the state versioning is managed via the following properties
on the `React.Component` class: `this.state` (start state) and `this.setState`
(the change).
- In both cases the function that actually creates the change is handled via an
arrow function. With the hook we use the customary name `handleClick` .
- The same process is managed in the hook via the `useState()` method. We
effectively set 'before' and 'after' destructured variables on this method:
```jsx
const [counter, setCounter] = useState(0);
// Schematically:
const [val, setVal] = useState(initialVal);
```
## Binding with class component state
In the class component example we use an inline arrow function to execute
`addOne()` however the official way to do it is to bind the event via the
constructor method to avoid the problems created by `this` scope in classes.
Using arrows is mostly fine and is less verbose, but it is important to
understand the 'official' approach.
The way to write the state change in this way is:
```jsx
class CounterClass extends React.Component{
constructor(props){
super(props);
this.state = { counterValue: 0};
this.handleClick = this.handleClick.bind(this); // bind the click to the class scope
}
handleClick(event){
this.setState({
counterValue: this.state.counterValue + 1;
});
}
render(){
return (
<button type="button"
onClick={this.handleClick}> // reference the class scope with `this`
Click Me
</button>
<CounterBox counterValue={this.state.counterValue}></CounterBox>
);
}
}
```
## How hooks improve on class components
- State, when managed via hooks can be easily decoupled from a specific
component and reused elsewhere. This also means it can be tested separately
from any specific component where it is applied. This is much harder to do
with classes which are closely entangled with the non-state aspects of a
component through `this` and binding:
> With Hooks, you can extract stateful logic from a component so it can be
> tested independently and reused. Hooks allow you to reuse stateful logic
> without changing your component hierarchy. This makes it easy to share Hooks
> among many components or with the community.
- Hooks simplify lifestyle methods and the use of `componentDidMount` etc
through the `useEffect` hook
- Classes and `this` are confusing generally. Functions are easier to grasp and
read.
## Relation to function components
You can think of hooks as function components (previously known as stateless
components) plus state. Previously function components were 'dumb' components.
That is, they didn't allow for state management and generally used for layout.
They could receive data as props but not state. This changes with hooks: you can
add state to functions and no longer need to use classes exclusively for state.
In fact you no longer need to use classes at all, unless you want to.
> The stateful portion of a function component must be placed before the
> `return()` statement in the function.