[React, TS] importしたComponentにonClickを直接書いてみた

2 min読了の目安(約1800字TECH技術記事

Reactでは親から子コンポーネントに関数を渡して実行できます。

import CartIcon from '../components/cart-icon.component'

interface Props {}

const toggleCartHiddenHandler = () => {
    ...
}

const Header: React.FC<Props> = () => (
  <CartIcon onToggle={toggleCartHiddenHandler} />
)

export default Header

疑問に思ったのですが、onClickをimportしたComponentに直接書けば
実行できるんじゃない?と思い試してみたので結果を載せてみます。

修正後のコード

// header.component.tsx
import React from 'react'
import CartIcon from '../components/cart-icon.component'

interface HeaderProps {}

const toggleCartHidden = () => {
    ...
}

const Header: React.FC<HeaderProps> = () => (
  // ここを引数渡しからonClickに
  <CartIcon onClick={() => toggleCartHidden()} />
)

export default Header
// cart-icon.component.tsx
import React from 'react'
interface CartIconProps {}

const CartIcon: React.FC<CartIconProps> = () => (
  <div></div>
)

export default CartIcon

これをビルドすると、onClickの部分でエラーがでました。

Type '{ onClick: () => toggleCartHidden(); }' is not assignable to type 'IntrinsicAttributes & { children?: ReactNode; }'
Property 'onClick' does not exist on type 'IntrinsicAttributes & { children?: ReactNode; }'.  TS2322


{ onClick: () => toggleCartHidden(); }''IntrinsicAttributes & { children?: ReactNode; }'という型に存在しないぞ、というエラーです。


IntrinsicAttributes & { children?: ReactNode; }とは?

まずですが、これなにかがわかっていませんでした。
調べたところ、React.FC<props>の、propsの型定義の一部です。


となると

CartIconというComponentに指定したonClickが、propsの一部としてtsに捉えられてしまったみたいですね。

なのでイベントハンドラは、importしたComponentに直接書くのではなく、 そのComponent内部で書かないといけない、ということですね。


まとめ

1.
ComponentでonClickとかのイベントを実行したいなら、
そのイベント関数をComponentに渡してComponentに実行させる必要がある

Bad
<CartIcon onClick={() => toggleCartHidden()} />

Good(引数として渡す)
<CartIcon onToggle={toggleCartHidden} />

2.
どのComponentがそのイベントを実行するべきなのか、
どのComponentで実行できれば十分なのか考え直すこと