Transform Class React Components to Functional

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.

Common Replacements

Definition

From

1
class (\w+) extends Component \{

To

1
const $1: FC = () => {
  • It’s for situation without export and props.

From

1
(export) default class (\w+) extends Component \{

To

1
$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

1
this\.(state\.|props\.)?

To

1
 
  • Assume that props is destructed uniformly.

Lift Cycle functions

From

1
componentDidMount() {

To

1
useEffect(() => {}, []);
  • componentDidUpdate can also be transformed to useEffect, with appropriate dependencies.
  • componentWillUnmount can be transformed to return function of corresponding useEffect handler.

From

1
2
3
state = {
data: null,
};

To

1
const [data, setData] = useState();

From

1
2
3
this.setState({
data,
});

To

1
setData(data)

Class Methods

From

1
^(\s*)(\w+)\((\w*)\) \{

To

1
$1const $2 = ($3) => {
  • It’s for regular function definition.
  • $1 is white spaces, $2 is method name, $3 is parameters

From

1
^(\s*)((\w+) = (async )?\((\w+(, )?)*\) =>)

To

1
$1const $2
  • It’s for arrow function definition.
  • $1 is white spaces, $2 is everything from the method name.

Class Getter

From

1
^(\s*)(get) (\w+)\(\)

To

1
$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

1
2
3
4
5
render() {
return (
<></>
);
}

To

1
2
3
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.