🕌

Reactでpropsにスプレッド構文を使った場合にclassNameが意図通り適用されない

2021/09/16に公開1

ハマったのでメモ。
以下のような Text Component があるとする。
このコンポーネントでは div をラップしているので、Props には HTMLDivElement の attributes をユニオンしており、onClick などをいちいち定義しなくてよいようにしている。

export type Props = React.HTMLAttributes<HTMLDivElement> & {
  size: number;
  weight?: Weight;
  align?: Align;
  className?: string;
};
const Text: React.FC<Props> = (props) => {
  const { size, weight, block = false, align, className, children } = props;

  const className2 = "hoge";
  return (
    <div className={clsx(className, className2)} {...props} block={block}>
      {children}
      {style.styles}
    </div>
  );
};

{...props}と記述して onClick などのプロパティを展開して div 適用しているが、classNameが意図した値にならない。
これはスプレッド構文によりclassNameが上書きされたためであり、この場合だとclassName2が適用されない。
なので記述する順番を考慮し以下のようにスプレッド構文は先頭に書く。

const Text: React.FC<Props> = (props) => {
  const { size, weight, block = false, align, className, children } = props;

  const className2 = "hoge";
  return (
    <div {...props} className={clsx(className, className2)} block={block}>
      {children}
      {style.styles}
    </div>
  );
};

コンポーネント props をスプレッド展開する場合は先頭じゃないとだめ!的な eslint があると嬉しいなあ。

Discussion

merutinmerutin

props直接渡すんじゃなくて、分割代入したほうが明示的になっていいと思います!

// divに渡すのはotherにする
 const { size, weight, block = false, align, className, children, ...other } = props;