Migrate classes to functional components

Replace class with functional component:

// before
class MyComponent extends React.Component<Props, State> {
// ...
}
 
// after
const MyComponent = () => // ...
 

Replace state with useState (use one hook per state)

// before
// declaration
  override state = {
    storeReady: false,
    navigationReady: false,
    animationFinished: false,
  };
// usage
this.setState({...state, storeReady: true}, optionalCallback);
<>{this.state.storeReady}</>
 
// after
// declaration
const [storeReady, setStoreReady] = useState(false);
const [navigationReady, setNavigationReady] = useState(false);
const [animationFinished, setAnimationFinished] = useState(false);
 
// usage
setStoreReady(true);
<>{storeReady}</>
 
// if optionalCallback rethink usage first, or as a quickwin use something similar to https://stackoverflow.com/a/61612292
useEffect(() => {
    if (storeReadyHasChanged) {
      optionalCallback();
    }
  }, [storeReady]);
 

Replace componentDidMount and componentWillUnmount with useEffect

// after
useEffect(() => {
  componentDidMount();
  return () => componentWillUnmount();
}, []);

Replace componentDidCatch with an ErrorBoundary wrapper

// before
// class MyComponent...
componenentDidCatch(error, infos) {
  handleError();
  throw error;
}
 
render () {
return <>...</>
}
 
// after
// const MyComponent...
return <MyErrorBoundary>...</MyErrorBoundary>;
 
// + extract another component
class ErrorBoundary extends React.Component {
  override componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
    captureException(error);
    throw error;
  }
 
  override render() {
    return this.props.children;
  }
}

After initial replacement, check for possible logical grouping, for example an effect that fetches a state can be extracted in a dedicated hook.

Redux

Replace mapStateToProps with useSelector

// before
const Component = ({derivedState}) => ...
const mapStateToProps = (state) => ({derivedState: selectDerivedState(state)})
connect(mapStateToProps)(Component)
 
// after
const Component = () => {
  const derivedState = useSelector(selectDerivedState)
	return ...
}

i18next

Replace withTranslation HOC with useTranslation

more one i18next: https://react.i18next.com/latest/usetranslation-hook (opens in a new tab)

// before
withTranslation([i18nNS])(Component)
 
// after
const { t, i18n } = useTranslation([i18nNS]);

React navigation

remove prop drilling navigation, use useNavigation instead

const navigation = useNavigation();
CC BY-NC 4.0 2024 © Shu Ding.