Registry
Explore community-led codemods to migrate, optimize, and transform your codebase.
Ready to contribute?
Build your own codemod and share it with the community.
Explore community-led codemods to migrate, optimize, and transform your codebase.
Build your own codemod and share it with the community.
Explore community-led codemods to migrate, optimize, and transform your codebase.
Transform React class components to modern function components
## Example This codemod turns X into Y. It also does Z. Note: this is a contrived example. Please modify it. ### Before ```ts import React from 'react'; import PropTypes from 'prop-types'; import { makeStyles, useTheme } from '@material-ui/styles'; import classNames from 'classnames'; import Button from '../../../../components/controls/Button'; import ButtonLoader from '../../../../components/loaders/ButtonLoader'; import makeStateElementName from '../../../../theme-editor/utils/makeStateElementName'; const useStyles = makeStyles((theme) => ({ stakeButton: ({ editorId }) => ({ width: '100%', height: 40, fontWeight: 600, ...theme[editorId], }), stakeButtonDisabled: ({ editorId }) => ({ ...theme[`${makeStateElementName(editorId, 'disabled')}`], }), '@media (hover: hover)': { stakeButtonDisabled: ({ editorId }) => ({ '&:hover': { ...theme[`${makeStateElementName(editorId, 'disabled')}`], }, }), }, loaderContainer: { width: '100%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', }, })); const StakeInputButton = ({ onClick, isDisabled, children, className, isLoading, dataEditorId, }) => { const classes = useStyles({ editorId: dataEditorId }); const theme = useTheme(); return ( < Button elementClasses = { { default: classNames(classes.stakeButton, className), disabled: classes.stakeButtonDisabled, } } disabled = { isDisabled } onClick = { onClick } style = { { padding: 0, } } dataEditorId = { dataEditorId } > { isLoading ? ( < div className = { classes.loaderContainer } > < ButtonLoader color = { theme.brandButton.color } /> < /div> ) : ( children ) } < /Button> ); }; StakeInputButton.propTypes = { dataEditorId: PropTypes.string, }; StakeInputButton.defaultProps = { dataEditorId: 'betslipPlaceBetButton', }; export default StakeInputButton; ``` ### After ```ts import React from 'react'; import PropTypes from 'prop-types'; import { makeStyles, useTheme } from '@material-ui/styles'; import classNames from 'classnames'; import Button from '../../../../components/controls/Button'; import ButtonLoader from '../../../../components/loaders/ButtonLoader'; import makeStateElementName from '../../../../theme-editor/utils/makeStateElementName'; const useStyles = makeStyles((theme) => ({ stakeButton: ({ editorId }) => ({ width: '100%', height: 40, fontWeight: 600, ...theme[editorId], }), stakeButtonDisabled: ({ editorId }) => ({ ...theme[`${makeStateElementName(editorId, 'disabled')}`], }), '@media (hover: hover)': { stakeButtonDisabled: ({ editorId }) => ({ '&:hover': { ...theme[`${makeStateElementName(editorId, 'disabled')}`], }, }), }, loaderContainer: { width: '100%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', }, })); const StakeInputButton = ({ onClick, isDisabled, children, className, isLoading, dataEditorId = 'betslipPlaceBetButton', }) => { const classes = useStyles({ editorId: dataEditorId }); const theme = useTheme(); return ( < Button elementClasses = { { default: classNames(classes.stakeButton, className), disabled: classes.stakeButtonDisabled, } } disabled = { isDisabled } onClick = { onClick } style = { { padding: 0, } } dataEditorId = { dataEditorId } > { isLoading ? ( < div className = { classes.loaderContainer } > < ButtonLoader color = { theme.brandButton.color } /> < /div> ) : ( children ) } < /Button> ); }; StakeInputButton.propTypes = { dataEditorId: PropTypes.string, }; export default StakeInputButton; ``` ,This codemod turns X into Y. It also does Z. Note: this is a contrived example. Please modify it. ### Before ```ts // In react 19 default props should be replaced with js default function parameters import React from 'react'; import PropTypes from 'prop-types'; import { useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; import { makeStyles } from '@material-ui/styles'; import classNames from 'classnames'; import Button from '../../../components/controls/Button'; import { selectors as betsSelectors } from '../../../redux/ducks/bets'; import useOfflineBooking from '../hooks/useOfflineBooking'; const useStyles = makeStyles({ bookingButton: { width: '100%', fontWeight: 600, }, }); const BookingCodeBookButton = ({ className, dataEditorId }) => { const { makeBooking } = useOfflineBooking(); const { t } = useTranslation(); const classes = useStyles(); const selectionsValid = useSelector(betsSelectors.selectSelectionsValid); return ( < Button className = { classNames(classes.bookingButton, className) } disabled = {!selectionsValid } onClick = { () => (selectionsValid ? makeBooking() : null) } dataEditorId = { dataEditorId } > { t('Book') } < /Button> ); }; BookingCodeBookButton.propTypes = { className: PropTypes.string, dataEditorId: PropTypes.string, }; BookingCodeBookButton.defaultProps = { className: null, dataEditorId: 'betslipShareButton', }; export default BookingCodeBookButton; ``` ### After ```ts import React from 'react'; import PropTypes from 'prop-types'; import { useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; import { makeStyles } from '@material-ui/styles'; import classNames from 'classnames'; import Button from '../../../components/controls/Button'; import { selectors as betsSelectors } from '../../../redux/ducks/bets'; import useOfflineBooking from '../hooks/useOfflineBooking'; const useStyles = makeStyles({ bookingButton: { width: '100%', fontWeight: 600, }, }); const BookingCodeBookButton = ({ className = null, dataEditorId = 'betslipShareButton', }) => { const { makeBooking } = useOfflineBooking(); const { t } = useTranslation(); const classes = useStyles(); const selectionsValid = useSelector(betsSelectors.selectSelectionsValid); return ( < Button className = { classNames(classes.bookingButton, className) } disabled = {!selectionsValid } onClick = { () => (selectionsValid ? makeBooking() : null) } dataEditorId = { dataEditorId } > { t('Book') } < /Button> ); }; BookingCodeBookButton.propTypes = { className: PropTypes.string, dataEditorId: PropTypes.string, }; export default BookingCodeBookButton; ``` ,This codemod turns X into Y. It also does Z. Note: this is a contrived example. Please modify it. ### Before ```ts // do not add new parameter if default props exist but is not defined in function parameters import React from 'react'; import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; import { makeStyles, useTheme } from '@material-ui/styles'; import ButtonArrow from '../../../../components/controls/ButtonArrow'; import SliderPoints from '../../../../components/controls/SliderPoints'; import BetSlipBonusesSlider from '../../BetSlipBonusesSlider'; import BetSlipEmptyBlock from '../../BetSlipTable/BetSlipEmptyBlock'; const useStyles = makeStyles((theme) => ({ bonusesListContainer: { background: theme.bonusPopup.background, color: theme.bonusPopup.color, paddingBottom: 20, overflowY: 'auto', boxSizing: 'border-box', }, points: { maxWidth: 200, margin: '0 auto', }, topLine: { marginBottom: 8, padding: '8px 16px', }, betSlipEmptyBlock: { minHeight: 275, }, })); const BetSlipBonusesListBase = ({ slides, currentSlide, setCurrentSlide, onCloseButtonClick, className, maxHeight, }) => { const theme = useTheme(); const classes = useStyles(); const { t } = useTranslation(); const arrowButtonBackground = theme.bonusPopup.background; return ( < div className = { `${classes.bonusesListContainer} ${className}` } style = { { maxHeight } } > < div className = { classes.topLine } > < ButtonArrow backgroundColor = { arrowButtonBackground } label = { t('Back') } onClick = { onCloseButtonClick } size = { 32 } direction = 'left' / > < /div> { slides.length > 0 ? ( < > < BetSlipBonusesSlider items = { slides } currentSlide = { currentSlide } setCurrentSlide = { setCurrentSlide } /> { !!slides.length && ( < div className = { classes.points } > < SliderPoints count = { slides.length } activeIndex = { currentSlide } color = { theme.bonusPopup.color } activeColor = { theme.bonusPopup.color } /> < /div> ) } < /> ) : ( < BetSlipEmptyBlock text = { t('No available Bonuses at this moment') } className = { classes.betSlipEmptyBlock } /> ) } < /div> ); }; BetSlipBonusesListBase.propTypes = { className: PropTypes.string, placeholder: PropTypes.string, // for widgets showBonusesForBet: PropTypes.string, toggleChooseBonusBlock: PropTypes.func.isRequired, onUseBonus: PropTypes.func.isRequired, onActivateBonus: PropTypes.func.isRequired, availableBonusesIds: PropTypes.arrayOf(PropTypes.string), bonuses: PropTypes.objectOf(PropTypes.shape({})).isRequired, }; BetSlipBonusesListBase.defaultProps = { placeholder: null, className: null, showBonusesForBet: null, availableBonusesIds: null, }; export default BetSlipBonusesListBase; ``` ### After ```ts import React from 'react'; import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; import { makeStyles, useTheme } from '@material-ui/styles'; import ButtonArrow from '../../../../components/controls/ButtonArrow'; import SliderPoints from '../../../../components/controls/SliderPoints'; import BetSlipBonusesSlider from '../../BetSlipBonusesSlider'; import BetSlipEmptyBlock from '../../BetSlipTable/BetSlipEmptyBlock'; const useStyles = makeStyles((theme) => ({ bonusesListContainer: { background: theme.bonusPopup.background, color: theme.bonusPopup.color, paddingBottom: 20, overflowY: 'auto', boxSizing: 'border-box', }, points: { maxWidth: 200, margin: '0 auto', }, topLine: { marginBottom: 8, padding: '8px 16px', }, betSlipEmptyBlock: { minHeight: 275, }, })); const BetSlipBonusesListBase = ({ slides, currentSlide, setCurrentSlide, onCloseButtonClick, className = null, maxHeight, }) => { const theme = useTheme(); const classes = useStyles(); const { t } = useTranslation(); const arrowButtonBackground = theme.bonusPopup.background; return ( < div className = { `${classes.bonusesListContainer} ${className}` } style = { { maxHeight } } > < div className = { classes.topLine } > < ButtonArrow backgroundColor = { arrowButtonBackground } label = { t('Back') } onClick = { onCloseButtonClick } size = { 32 } direction = 'left' / > < /div> { slides.length > 0 ? ( < > < BetSlipBonusesSlider items = { slides } currentSlide = { currentSlide } setCurrentSlide = { setCurrentSlide } /> { !!slides.length && ( < div className = { classes.points } > < SliderPoints count = { slides.length } activeIndex = { currentSlide } color = { theme.bonusPopup.color } activeColor = { theme.bonusPopup.color } /> < /div> ) } < /> ) : ( < BetSlipEmptyBlock text = { t('No available Bonuses at this moment') } className = { classes.betSlipEmptyBlock } /> ) } < /div> ); }; BetSlipBonusesListBase.propTypes = { className: PropTypes.string, placeholder: PropTypes.string, // for widgets showBonusesForBet: PropTypes.string, toggleChooseBonusBlock: PropTypes.func.isRequired, onUseBonus: PropTypes.func.isRequired, onActivateBonus: PropTypes.func.isRequired, availableBonusesIds: PropTypes.arrayOf(PropTypes.string), bonuses: PropTypes.objectOf(PropTypes.shape({})).isRequired, }; export default BetSlipBonusesListBase; ```
- Replaces usages of `ReactDom.render()` with `createRoot(node).render()`. - Replaces usages of `ReactDom.hydrate()` with `hydrateRoot()` - Replaces usages of `ReactDom.unmountComponentAtNode()` with `root.unmount()` ## Example ### Before ```ts import ReactDom from "react-dom"; import Component from "Component"; ReactDom.render(<Component />, document.getElementById('app')); ``` ### After ```ts import { createRoot } from "react-dom/client"; import ReactDom from "react-dom"; import Component from "Component"; const root = createRoot(document.getElementById('app')); root.render(<Component />); ``` ### Before ```ts import ReactDom from "react-dom"; import Component from "Component"; ReactDom.hydrate(<Component />, document.getElementById("app")); ``` ### After ```ts import { hydrateRoot } from "react-dom/client"; import ReactDom from "react-dom"; import Component from "Component"; hydrateRoot(document.getElementById("app"), <Component />); ```
This codemod will replace the usages of `TestUtils.act()` to use `React.act()`, introduced in React v19. ## Example ### Before: ```ts import { act } from "react-dom/test-utils"; act(); ``` ### After: ```ts import { act } from "react"; act(); ``` ### Before: ```ts import * as ReactDOMTestUtils from "react-dom/test-utils"; ReactDOMTestUtils.act(); ``` ### After: ```ts import * as React from "react"; React.act(); ```
Codemod to convert React PropTypes to TypeScript types. - Supports function and class components - Supports `static propTypes` declarations on class components - Supports [`forwardRef`s](https://reactjs.org/docs/forwarding-refs.html) - Supports files with multiple components - Copies JSDoc comments to the generated TypeScript types - Option to remove or preserve PropTypes after converting to TS ## Before: ```jsx import PropTypes from "prop-types"; import React from "react"; export function MyComponent(props) { return <span />; } MyComponent.propTypes = { bar: PropTypes.string.isRequired, foo: PropTypes.number, }; ``` ## After: ```tsx import React from "react"; interface MyComponentProps { bar: string; foo?: number; } export function MyComponent(props: MyComponentProps) { return <span />; } ```
This codemod transforms React imports to use named imports instead of default or namespace imports. This helps reduce bundle size by allowing better tree-shaking of unused React exports. ### Before ```tsx import React from "react"; function MyComponent() { return React.createElement( "div", null, React.createElement(React.Fragment, null, "Hello"), ); } ``` ### After ```tsx import { createElement, Fragment } from "react"; function MyComponent() { return createElement("div", null, createElement(Fragment, null, "Hello")); } ```
This recipe is a set of codemods that will fix some of React 19 breaking changes. The recipe includes the following codemods: - react/19/replace-reactdom-render - react/19/replace-string-ref - react/19/replace-act-import - react/19/replace-use-form-state - react/prop-types-typescript
React.forwardRef will be deprecated for Function Components in near future. This codemod removes forwardRef function. ### Before: ```jsx import { forwardRef } from "react"; const MyInput = forwardRef(function MyInput(props, ref) { // ... }); ``` ### After: ```tsx const MyInput = function MyInput({ ref, ...props }) { // ... }; ```
This codemod will replace the usages of `useFormState()` to use `useActionState()`, introduced in React v19. ## Example ### Before: ```ts import { useFormState } from "react-dom"; async function increment(previousState, formData) { return previousState + 1; } function StatefulForm({}) { const [state, formAction] = useFormState(increment, 0); return ( <form> {state} <button formAction={formAction}>Increment</button> </form> ) } ``` ### After: ```ts import { useActionState } from "react"; async function increment(previousState, formData) { return previousState + 1; } function StatefulForm({}) { const [state, formAction] = useActionState(increment, 0); return ( <form> {state} <button formAction={formAction}>Increment</button> </form> ) } ``` ### Before: ```ts import * as ReactDOM from "react-dom"; function StatefulForm({}) { const [state, formAction] = ReactDOM.useFormState(increment, 0); return <form></form>; } ``` ### After: ```ts import { useActionState } from "react"; function StatefulForm({}) { const [state, formAction] = useActionState(increment, 0); return <form></form>; } ```
This codemod will remove manual memoization hooks: `useCallback`, `useMemo` and `memo`. This codemod goes hand in hand with React Compiler. > Please note that this is not a safe codemod, as the compiler isn't 1-1 with inserting useMemo/useCallback, so there may be some occurrences that need to be kept in order to keep the semantics. ## Example ### Before: ```tsx import { memo } from "react"; const MyComponent = ({ name }) => { return <div>Hello, {name}!</div>; }; const MemoizedMyComponent = memo(MyComponent); ``` ### After: ```tsx const MyComponent = ({ name }) => { return <div>Hello, {name}!</div>; }; const MemoizedMyComponent = MyComponent; ```
This codemod will convert the usage of `useContext` to the new hook format, introduced in React v19. ## Example ### Before: ```tsx import { useContext } from "react"; import UseTheme from "./UseTheme"; const theme = useContext(UseTheme); ``` ### After: ```tsx import { use } from "react"; import UseTheme from "./UseTheme"; const theme = use(UseTheme); ```
This codemod transforms React.createElement calls into JSX syntax, making your code more readable and maintainable. ## Example ### Before ```tsx return React.createElement( "div", { className: "container" }, React.createElement("h1", null, "Hello World"), React.createElement("p", { style: { color: "blue" } }, "Welcome to React") ); ``` ### After ```tsx return ( <div className="container"> <h1>Hello World</h1> <p style={{ color: "blue" }}>Welcome to React</p> </div> ); ```
Build your own codemod and share it with the community.