
Research
Two Malicious Rust Crates Impersonate Popular Logger to Steal Wallet Keys
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
react-declassify
Advanced tools
This codemod automatically transforms React class components into React functional components using Hooks for you!
Before | After |
---|---|
![]() | ![]() |
Class components are still going to be supported by React for the foreseeable future. However, it is no longer recommended to write new components in class-style.
So what about the existing components? Although React will continue to support these, you may struggle to maintain them because:
Thus it is still a good idea to migrate from class components to Hooks-based components.
However, as this is not a simple syntactic change, migration needs a careful hand work and a careful review. This tool is a classic automation, it reduces a risk of introducing human errors during migration.
yarn add -D @codemod/cli react-declassify
# OR
npm install -D @codemod/cli react-declassify
then
npx codemod --plugin react-declassify 'src/**/*.tsx'
Before:
import React from "react";
type Props = {
by: number;
};
type State = {
counter: number;
};
export class C extends React.Component<Props, State> {
static defaultProps = {
by: 1
};
constructor(props) {
super(props);
this.state = {
counter: 0
};
}
render() {
return (
<>
<button onClick={() => this.onClick()}>
{this.state.counter}
</button>
<p>Current step: {this.props.by}</p>
</>
);
}
onClick() {
this.setState({ counter: this.state.counter + this.props.by });
}
}
After:
import React from "react";
type Props = {
by?: number | undefined
};
type State = {
counter: number;
};
export const C: React.FC<Props> = props => {
const {
by = 1
} = props;
const [counter, setCounter] = React.useState<number>(0);
function onClick() {
setCounter(counter + by);
}
return <>
<button onClick={() => onClick()}>
{counter}
</button>
<p>Current step: {by}</p>
</>;
};
Before:
import React from "react";
export class C extends React.Component {
render() {
const { text, color } = this.props;
return <button style={{ color }} onClick={() => this.onClick()}>{text}</button>;
}
onClick() {
const { text, handleClick } = this.props;
alert(`${text} was clicked!`);
handleClick();
}
}
After:
import React from "react";
export const C = props => {
const {
text,
color,
handleClick
} = props;
function onClick() {
alert(`${text} was clicked!`);
handleClick();
}
return <button style={{ color }} onClick={() => onClick()}>{text}</button>;
};
Hard errors are indicated by /* react-declassify-disable Cannot perform transformation */
.
Soft errors are indicated by special variable names including:
TODO_this
Hard errors stop transformation of the whole class while stop errors do not. You need to fix the errors to conclude transformation.
Adding to the class a comment including react-declassify-disable
will disable transformation of that class.
/* react-declassify-disable */
class MyComponent extends React.Component {}
Marking the component class as abstract
or /** @abstract */
also disables transformation.
The codemod follows your import style from the extends
clause. So
import React from "react";
class MyComponent extends React.Component {}
is transformed to
import React from "react";
const MyComponent: React.FC = () => {};
whereas
import { Component } from "react";
class MyComponent extends Component {}
is transformed to
import { Component, FC } from "react";
const MyComponent: FC = () => {};
It cannot be configured to mix these styles. For example it cannot emit React.FC
for typing while emitting useState
(not React.useState
) for hooks.
Class components may receive refs; this is to be supported in the future. Once it is implemented, you will be able to add special directives in the component to enable the feature.
This codemod relies on recast for pretty-printing and sometimes generates code that does not match your preferred style. This is ineviable. For example it does not currently emit parentheses for the arrow function:
const MyComponent: FC = props => {
// ^^^^^ no parentheses
// ...
};
We have no control over this choice. Even if it were possible, allowing configurations on styles would make the codemod unnecessarily complex.
If you need to enforce specific styles, use Prettier or ESLint or whatever is your favorite to reformat the code after you apply the transformation.
React.Component
React.PureComponent
export default class
declarationsReact.FC
annotationP
type argumentS
type argumentchildren
seems to be usedthis.props
this.props
to props
parameterprops
if necessarythis.props
defaultProps
function
sfunction
suseCallback
if deemed necessarythis.props.onClick()
) to indirect callonClick={this.onClick.bind(this)}
)this.onClick = this.onClick.bind(this)
)this.state
this.state
into useState
variablescreateRef
to useRef
useRef
forwardRef
+ useImperativeHandle
when requested by the usercontextType
to useContext
contextTypes
static propTypes
to assignmentsrender
if necessaryYou get the following type error:
test.tsx:1:1 - error TS2322: Type '{ ... }' is not assignable to type 'IntrinsicAttributes & Props'.
Property 'ref' does not exist on type 'IntrinsicAttributes & Props'.
1 ref={ref}
~~~
or you receive the following warning in the console:
Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
Check the render method of `C`.
at App
or you receive some sort of null error (e.g. Cannot read properties of undefined (reading 'a')
) because ref.current
is always undefined.
Type errors can also occur at useRef
in a component that uses the component under transformation:
test.tsx:1:1 - error TS2749: 'C' refers to a value, but is being used as a type here. Did you mean 'typeof C'?
41 const component = React.useRef<C | null>(null);
~
Class components receives refs, and the ref points to the instance of the class. Functional components do not receive refs by default.
This is not implemented now. However, once it is implemented you can opt in ref support by certain directives. It will generate forwardRef
+ useImperativeHandle
to expose necessary APIs.
You get the following type error:
test.tsx:1:1 - error TS2322: Type '(props: Props) => ReactNode' is not assignable to type 'FC<Props>'.
Type 'ReactNode' is not assignable to type 'ReactElement<any, any> | null'.
1 const C: React.FC<Props> = (props) => {
~
In DefinitelyTyped, React.FC
is typed slightly stricter than the render
method. You are expected a single element or null
.
We leave this untransformed because it is known not to cause problems at runtime.
An extra layer of a frament <> ... </>
suffices to fix the type error.
this.props
or this.state
. This assumption is necessary because there is a difference between class components and funtion components in how the callbacks capture props or states. To transform the code in an idiomatic way, this assumption is necessary.this
value as the one when the method is referenced.undefined
to this.setState
. We need to replace various functionalities associated with this
with alternative tools and the transformation relies on the fact that the value of this
is stable all across the class lifecycle.0.2.0
TODO_this
to indicate errors and continue transformation.FAQs
say goodbye to class components [EXPERIMENTAL]
We found that react-declassify demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
Research
A malicious package uses a QR code as steganography in an innovative technique.
Research
/Security News
Socket identified 80 fake candidates targeting engineering roles, including suspected North Korean operators, exposing the new reality of hiring as a security function.