Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions crates/oxc_linter/src/rules/react/jsx_no_comment_textnodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,32 @@ pub struct JsxNoCommentTextnodes;
declare_oxc_lint!(
/// ### What it does
///
/// This rule prevents comment strings (e.g. beginning with `//` or `/*`) from being accidentally injected as a text node in JSX statements.
/// This rule prevents comment strings (e.g. beginning with `//` or `/*`) from being
/// accidentally injected as a text node in JSX statements.
///
/// ### Why is this bad?
///
/// In JSX, any text node that is not wrapped in curly braces is considered a literal string to be rendered. This can lead to unexpected behavior when the text contains a comment.
/// In JSX, any text node that is not wrapped in curly braces is considered
/// a literal string to be rendered. This can lead to unexpected behavior
/// when the text contains a comment.
///
/// ### Examples
///
/// Examples of **incorrect** code for this rule:
/// ```jsx
/// const Hello = () => {
/// return <div>// empty div</div>;
/// return <div>// empty div</div>;
/// }
///
/// const Hello = () => {
/// return <div>/* empty div */</div>;
/// return <div>/* empty div */</div>;
/// }
///
/// ```
///
/// Examples of **correct** code for this rule:
/// ```jsx
/// const Hello = () => {
/// return <div>{/* empty div */}</div>;
/// return <div>{/* empty div */}</div>;
/// }
/// ```
JsxNoCommentTextnodes,
Expand Down
18 changes: 5 additions & 13 deletions crates/oxc_linter/src/rules/react/no_did_mount_set_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ fn no_did_mount_set_state_diagnostic(span: Span) -> OxcDiagnostic {
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "kebab-case")]
pub enum NoDidMountSetStateConfig {
/// Allow `setState` calls in nested functions within `componentDidMount`, the default behavior.
#[default]
#[serde(skip)]
Allowed,
/// When set, also disallows `setState` calls in nested functions within `componentDidMount`.
DisallowInFunc,
}

Expand All @@ -35,6 +36,9 @@ declare_oxc_lint!(
///
/// Disallows using `setState` in the `componentDidMount` lifecycle method.
///
/// This rule is not relevant for function components, and so can potentially be
/// disabled for modern React codebases.
///
/// ### Why is this bad?
///
/// Updating the state after a component mount will trigger a second `render()` call and can lead to property/layout thrashing.
Expand Down Expand Up @@ -71,18 +75,6 @@ declare_oxc_lint!(
/// }
/// });
/// ```
///
/// ### Options
///
/// The rule accepts a string value `"disallow-in-func"`:
///
/// ```json
/// {
/// "react/no-did-mount-set-state": ["error", "disallow-in-func"]
/// }
/// ```
///
/// When set, also disallows `setState` calls in nested functions within `componentDidMount`.
NoDidMountSetState,
react,
correctness,
Expand Down
91 changes: 51 additions & 40 deletions crates/oxc_linter/src/rules/react/no_direct_mutation_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ use crate::{
};

fn no_direct_mutation_state_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("never mutate this.state directly.")
.with_help("calling setState() afterwards may replace the mutation you made.")
OxcDiagnostic::warn("Never mutate `this.state` directly.")
.with_help(
"Calling `setState()` afterwards will replace the mutations you made via `this.state`.",
)
.with_label(span)
}

Expand All @@ -27,55 +29,64 @@ pub struct NoDirectMutationState;
declare_oxc_lint!(
/// ### What it does
///
/// The restriction coder cannot directly change the value of this.state
/// This rule forbids the direct mutation of `this.state` in React components.
///
/// Note that this rule only applies to class components, it does not apply to function
/// components. For modern React codebases, this rule may not be necessary or relevant.
///
/// ### Why is this bad?
///
/// calling setState() afterwards may replace the mutation you made
/// React components should *never* mutate `this.state` directly, as
/// calling `setState()` afterwards may replace the mutation you made.
///
/// `this.state` should be treated as if it were immutable.
///
/// ### Examples
///
/// Examples of **incorrect** code for this rule:
/// ```jsx
/// // error
/// var Hello = createReactClass({
/// componentDidMount: function() {
/// this.state.name = this.props.name.toUpperCase();
/// },
/// render: function() {
/// return <div>Hello {this.state.name}</div>;
/// }
/// });
/// var Hello = createReactClass({
/// componentDidMount: function() {
/// this.state.name = this.props.name.toUpperCase();
/// },
/// render: function() {
/// return <div>Hello {this.state.name}</div>;
/// }
/// });
///
/// class Hello extends React.Component {
/// constructor(props) {
/// super(props)
/// class Hello extends React.Component {
/// constructor(props) {
/// super(props)
///
/// doSomethingAsync(() => {
/// this.state = 'bad';
/// });
/// }
/// }
/// doSomethingAsync(() => {
/// this.state = 'bad';
/// });
/// }
/// }
/// ```
///
/// // success
/// var Hello = createReactClass({
/// componentDidMount: function() {
/// this.setState({
/// name: this.props.name.toUpperCase();
/// });
/// },
/// render: function() {
/// return <div>Hello {this.state.name}</div>;
/// }
/// });
/// Examples of **correct** code for this rule:
/// ```jsx
/// var Hello = createReactClass({
/// componentDidMount: function() {
/// this.setState({
/// name: this.props.name.toUpperCase();
/// });
/// },
/// render: function() {
/// return <div>Hello {this.state.name}</div>;
/// }
/// });
///
/// class Hello extends React.Component {
/// constructor(props) {
/// super(props)
/// class Hello extends React.Component {
/// constructor(props) {
/// super(props)
///
/// this.state = {
/// foo: 'bar',
/// }
/// }
/// }
/// this.state = {
/// foo: 'bar',
/// }
/// }
/// }
/// ```
NoDirectMutationState,
react,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ declare_oxc_lint!(
///
/// Disallow usage of `shouldComponentUpdate` when extending `React.PureComponent`.
///
/// Note that usage of `PureComponent` is
/// [not recommended in modern React](https://react.dev/reference/react/PureComponent).
///
/// ### Why is this bad?
///
/// `React.PureComponent` automatically implements `shouldComponentUpdate` with a shallow prop and state comparison.
Expand Down
11 changes: 8 additions & 3 deletions crates/oxc_linter/src/rules/react/no_render_return_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,20 @@ declare_oxc_lint!(
///
/// ### Why is this bad?
///
/// Using the return value from `ReactDOM.render()` is a legacy feature and should not be used.
/// Using the return value from `ReactDOM.render()` is a legacy
/// feature and should not be used.
///
/// Note that `ReactDOM.render`
/// [has been removed entirely in React 19](https://react.dev/blog/2024/04/25/react-19-upgrade-guide#removed-reactdom-render)
/// and so should generally not be used.
///
/// ### Examples
///
/// Examples of **incorrect** code for this rule:
/// ```jsx
/// vaa inst =ReactDOM.render(<App />, document.body);
/// var inst = ReactDOM.render(<App />, document.body);
/// function render() {
/// return ReactDOM.render(<App />, document.body);
/// return ReactDOM.render(<App />, document.body);
/// }
/// ```
///
Expand Down
12 changes: 8 additions & 4 deletions crates/oxc_linter/src/rules/react/require_render_return.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ use crate::{
};

fn require_render_return_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Your render method should have a return statement")
.with_help("When writing the `render` method in a component it is easy to forget to return the JSX content. This rule will warn if the return statement is missing.")
OxcDiagnostic::warn("Your `render` method should have a `return` statement.")
.with_help("When writing the `render` method in a component it is easy to forget to return the JSX content. This rule will warn if the `return` statement is missing.")
.with_label(span)
}

Expand All @@ -26,11 +26,15 @@ pub struct RequireRenderReturn;
declare_oxc_lint!(
/// ### What it does
///
/// Enforce ES5 or ES2015 class for returning value in render function
/// Enforce ES5 or ES2015 class for returning value in the `render` function.
///
/// This rule is not relevant for function components, and so can potentially be
/// disabled for modern React codebases.
///
/// ### Why is this bad?
///
/// When writing the `render` method in a component it is easy to forget to return the JSX content. This rule will warn if the return statement is missing.
/// When writing the `render` method in a component it is easy to forget to return the
/// JSX content. This rule will warn if the `return` statement is missing.
///
/// ### Examples
///
Expand Down
1 change: 1 addition & 0 deletions crates/oxc_linter/src/rules/react/self_closing_comp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ fn test() {
Some(serde_json::json!([{ "html": true }])),
),
];

Tester::new(SelfClosingComp::NAME, SelfClosingComp::PLUGIN, pass, fail)
.expect_fix(fix)
.test_and_snapshot();
Expand Down
21 changes: 10 additions & 11 deletions crates/oxc_linter/src/rules/react/state_in_constructor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ fn state_in_constructor_diagnostic(span: Span, is_state_init_constructor: bool)
#[serde(rename_all = "kebab-case")]
pub enum StateInConstructorConfig {
/// Enforce state initialization in the constructor.
/// This is the default mode.
#[default]
Always,
/// Enforce state initialization with a class property.
Expand Down Expand Up @@ -57,7 +58,11 @@ impl std::ops::Deref for StateInConstructor {
declare_oxc_lint!(
/// ### What it does
///
/// Enforces the state initialization style to be either in a constructor or with a class property.
/// Enforces the state initialization style to be either in a
/// constructor or with a class property.
///
/// This rule is not relevant for function components, and so can potentially be
/// disabled for modern React codebases.
///
/// ### Why is this bad?
///
Expand All @@ -66,13 +71,7 @@ declare_oxc_lint!(
///
/// ### Examples
///
/// This rule has two modes: `"always"` and `"never"`.
///
/// #### `"always"` mode
///
/// Will enforce the state initialization style to be in a constructor. This is the default mode.
///
/// Examples of **incorrect** code for this rule:
/// Examples of **incorrect** code for this rule by default, with `"always"` mode:
/// ```jsx
/// class Foo extends React.Component {
/// state = { bar: 0 }
Expand All @@ -82,7 +81,7 @@ declare_oxc_lint!(
/// }
/// ```
///
/// Examples of **correct** code for this rule:
/// Examples of **correct** code for this rule by default, with `"always"` mode:
/// ```jsx
/// class Foo extends React.Component {
/// constructor(props) {
Expand All @@ -99,7 +98,7 @@ declare_oxc_lint!(
///
/// Will enforce the state initialization style to be with a class property.
///
/// Examples of **incorrect** code for this rule:
/// Examples of **incorrect** code for this rule with `"never"` mode:
/// ```jsx
/// class Foo extends React.Component {
/// constructor(props) {
Expand All @@ -112,7 +111,7 @@ declare_oxc_lint!(
/// }
/// ```
///
/// Examples of **correct** code for this rule:
/// Examples of **correct** code for this rule with `"never"` mode:
/// ```jsx
/// class Foo extends React.Component {
/// state = { bar: 0 }
Expand Down
Loading
Loading