Transform Class React Components to Functional
Tags: react, functionalreactiveprogramming, regex
Published: 2023-12-30 11:06:12

As functional React components is more modern with support to hooks which is useful, it's common practice to rewrite the old styled class components to functional components. This article summarizes some common steps and pitfalls for the transformation.
<!-- more -->

## Common Replacements

### Definition
From
```
class (\w+) extends Component \{
```
To
```
const $1: FC = () => {
```
- It's for situation without `export` and `props`.

From
```
(export) default class (\w+) extends Component \{
```
To
```
$1 const $2: FC<$2Props> = () => {
```
- As the second captured word, `$2` is the component name.
- `$2Props` should be defined as the name of `props` interface.

### Attributes Prefix
From
```
this\.(state\.|props\.)?
```
To
```
 
```
- Assume that `props` is destructed uniformly.

### Lift Cycle functions

From
```
componentDidMount() { 
```
To
```
useEffect(() => {}, []);
```
- `componentDidUpdate` can also be transformed to `useEffect`, with appropriate dependencies.
- `componentWillUnmount` can be transformed to return function of corresponding `useEffect` handler.

### State Related Statement

From
```
state = {
  data: null,
};
```
To
```
const [data, setData] = useState();
```

From
```
this.setState({
  data,
});
```
To
```
setData(data)
```

### Class Methods
From
```
^(\s*)(\w+)\((\w*)\) \{
```
To
```
$1const $2 = ($3) => {
```
- It's for regular function definition.
- `$1` is white spaces, `$2` is method name, `$3` is parameters

From
```
^(\s*)((\w+) = (async )?\((\w+(, )?)*\) =>)
```
To
```
$1const $2
```
- It's for arrow function definition.
- `$1` is white spaces, `$2` is everything from the method name.

### Class Getter
From
```
^(\s*)(get) (\w+)\(\)
```
To
```
$1const $2\u$3 = () =>
```
- `\u` means capitalizing the following captured word.
- The invoking of the getter should have `()` after the name.
- If the getter is simple, it can be assign directly without function.

### Render function
From
```
render() {
  return (
    <></>
  );
}
```
To
```
return (
  <></>
);
```

## Notable Pitfalls

### Name Conflict
It's possible for class component to have the same name as `attributes` and `props`, such as `this.data` and `this.props.data`.
With `this.data` become `data`, and it's common to destruct `props` as `const {data} = props`, the name conflict comes.

### State Callback
With `this.setState`, we can set a callback to be invoked after the state is changed actually, but we have to change this implementation to `useEffect` with the changed state as dependency.

### Function as State
If the value of a state is a function, you wrap it into an anonymous function or else the hook version of `setState` will treat it as a callback.
Actually, in most case, this kind of state is not related to rendering, so perhaps `useRef` is more suitable for them.

This article shows some replacement with RegExp, which will make the transformation from class to functional component easier, and some pitfalls that you may encounter during the process for you to pay attention to, but to be sure, there can be more jobs for different scenarios.