logoESLint React
Rules

no-unstable-default-props

Prevents using referential-type values as default props in object destructuring.

Full Name in eslint-plugin-react-x

react-x/no-unstable-default-props

Full Name in @eslint-react/eslint-plugin

@eslint-react/no-unstable-default-props

Features

⚙️

Presets

strict strict-typescript strict-type-checked

Rule Details

When using object destructuring syntax, you can set the default value for a given property if it does not exist. If you set the default value to one of the values that is compared by identity, then each time the destructuring is evaluated the JS engine will create a new, distinct value in the destructured variable.

This harms performance, as it means that React will have to re-evaluate hooks and re-render memoized components more often than necessary.

To fix the violations, the easiest way is to use a referencing variable in module scope instead of using the literal values.

Common Violations

Invalid

interface MyComponentProps {
  items: string[];
}

function MyComponent({ items = [] }: MyComponentProps) {
  //                           ^^^ An 'Array literal' as a default prop. This could lead to a potential infinite render loop in React. Use a variable instead of 'Array literal'.
  return null;
}
interface MyComponentProps {
  items: Record<string, string>;
}

function MyComponent({ items = {} }: MyComponentProps) {
  //                           ^^^ An 'Object literal' as a default prop. This could lead to a potential infinite render loop in React. Use a variable instead of 'Object literal'.
  return null;
}
interface MyComponentProps {
  onClick: () => void;
}

function MyComponent({ onClick = () => {} }: MyComponentProps) {
  //                             ^^^ An 'arrow function expression' as a default prop. This could lead to a potential infinite render loop in React. Use a variable instead of 'arrow function expression'.
  return null;
}
interface MyComponentProps {
  items: string[];
}

function MyComponent(props: MyComponentProps) {
  const { items = [] } = props;
  //              ^^^ An 'Array literal' as a default prop. This could lead to a potential infinite render loop in React. Use a variable instead of 'Array literal'.
  return null;
}

Valid

import React from "react";

const emptyArray: string[] = [];

interface MyComponentProps {
  items: string[];
}

function MyComponent({ items = emptyArray }: MyComponentProps) {
  return null;
}
import React from "react";

const emptyObject = {};

interface MyComponentProps {
  items: Record<string, string>;
}

function MyComponent({ items = emptyObject }: MyComponentProps) {
  return null;
}
import React from "react";

const noop = () => {};

interface MyComponentProps {
  onClick: () => void;
}

function MyComponent({ onClick = noop }: MyComponentProps) {
  return null;
}
import React from "react";

const emptyArray: string[] = [];

interface MyComponentProps {
  items: string[];
}

function MyComponent(props: MyComponentProps) {
  const { items = emptyArray } = props;

  return null;
}
interface MyComponentProps {
  num: number;
  str: string;
  bool: boolean;
}

function MyComponent({ num = 3, str = "foo", bool = true }: MyComponentProps) {
  //                   ^^^ Primitives are all compared by value, so they are safe to inline as default props.
  return null;
}
"use memo";
interface MyComponentProps {
  items: string[];
}

function MyComponent({ items = [] }: MyComponentProps) {
  return null;
}

Rule Options

type Options = {
  safeDefaultProps?: string[];
};

safeDefaultProps

An array of identifier names or regex patterns that are safe to use as default props. If the default prop value is created by calling one of the allowlisted identifiers, it will be considered safe.

Default: []

Resources

Further Reading


See Also

On this page