Stripe UI拡張機能入門: ボタンクリックなどのイベントを設定する



この記事は、[Stripe Apps を25日間紹介し続ける Advent Calendar 2022](https://qiita.com/advent-calendar/2022/stripe-apps) 7日目の記事です。

![スクリーンショット 2022-11-24 17.56.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/e0261865-0418-daa2-423a-5f4d70558b1b.png)

アプリを開発する中で、「フォームへの情報入力」や「ボタンクリック」など、さまざまなユーザー操作を処理する必要があります。

この記事では、`@stripe/ui-extension-sdk`を使って、ボタンクリックなどのイベントを処理する方法を紹介します。

## コンポーネントごとの、`onXXX`プロパティで関数を設定する

クリックや入力などの操作を受け付けるコンポーネントには、`onPress`や`onChange`などのイベント処理用プロパティが用意されています。

例えばボタン要素の場合、`onPress`でクリック時に実行したい処理を記述できます。

```tsx
import { Button } from '@stripe/ui-extension-sdk/ui'
import { FC } from 'react'

const ExampleButton: FC = () => {
  return (
    <Button
      onPress={(e) => {
        console.log(e)
      }}
    >
      Click it!
    </Button>
  )
}
```

このボタンをクリックすると、ブラウザのコンソールにイベントの中身が表示されます。

![スクリーンショット 2022-12-05 14.40.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/db6bfe01-f373-36ac-6e38-0013b127ec09.png)

そのほかのコンポーネントについては、ドキュメントにてご確認ください。

https://stripe.com/docs/stripe-apps/components

### Tips: TypeScriptで、ハンドラー関数を型安全に作る方法

`onPress`などのイベントハンドラの型定義は、`React.ComponentProps`を利用して取得できます。

先ほどの`Button`コンポーネントの場合次のように書き換えることができます。

```diff_typescript

import { Button } from '@stripe/ui-extension-sdk/ui'
import { FC } from 'react'

+ type ButtonProps = React.ComponentProps<typeof Button>
const ExampleButton: FC = () => {
  const handleOnPress: ButtonProps['onPress'] = (e) => {
    console.log(e)
  }
  return (
    <Button
-      onPress={(e) => {
-        console.log(e)
-      }}
+      onPress={handleOnPress}
    >
      Click it!
    </Button>
  )
}
```

この書き方を覚えると、カスタムHookの作成などがやりやすくなりますので、ぜひお試しください。

## フォームを実装する際の注意点

通常、入力フォームを実装する際は、`form`タグの`submit`イベントで送信処理を行います。

ですがStripe Appsの場合、フォームについても`Button`の`onPress`で処理する必要があります。

```tsx
import { Box, ContextView, Button, Switch, FormFieldGroup, TextField } from "@stripe/ui-extension-sdk/ui";
import { FC } from 'react'

const FormExample: FC = () => {
  const handleSubmit: ButtonProps['onPress'] = (e) => {
    console.log(e)
  }
  return (
    <Box css={{
      gap: 'medium',
      stack: 'y',
    }}>
      <FormFieldGroup legend="Full name" description="Enter your full name">
        <TextField label="First name" placeholder="First name" hiddenElements={['label']} />
        <TextField label="Last name" placeholder="Last name" hiddenElements={['label']} />
      </FormFieldGroup>
      <FormFieldGroup legend="Spiffy settings" layout="column">
        <Switch label="Enable transmogrifier" description="Scientific progress goes 'boink'" />
        <Switch label="Set zorcher on 'shake and bake'" description="Note: blasters may be useless against slime" />
      </FormFieldGroup>
      <Box
        css={{
          alignSelfX: 'end'
        }}
      >
        <Button
          type="primary"
          onPress={handleSubmit}
        >
          Save
        </Button>
      </Box>
    </Box>
  )
}
```

このコードは、次のような見た目になります。

![スクリーンショット 2022-12-05 14.49.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/b92b819f-fc63-5ddf-9b0a-d6f1a61631b8.png)

入力値のハンドルをする場合は、`TextField`などの要素の`onChange`と`useState`を組み合わせます。

```tsx
import { Box, FormFieldGroup, TextField } from "@stripe/ui-extension-sdk/ui";
import { FC, useState } from 'react'

const Greeding: FC = () => {
  const [firstName, setFirstName] = useState('')
  const [lastName, setLastName] = useState('')
  return (
    <Box css={{
      gap: 'medium',
      stack: 'y',
    }}>
      <FormFieldGroup legend="Full name" description="Enter your full name">
        <TextField
          label="First name"
          placeholder="First name"
          hiddenElements={['label']}
          onChange={(e) => setFirstName(e.target.value)}
        />
        <TextField
          label="Last name"
          placeholder="Last name"
          hiddenElements={['label']}
          onChange={(e) => setLastName(e.target.value)}
        />
      </FormFieldGroup>
...
```

`value`プロパティがなく、`useState`などで入力値の制御ができない点にご注意ください。

初期パラメータを設定したい場合は、`defaultValue`を利用しましょう。

```diff_typescript

        <TextField
          label="Last name"
          placeholder="Last name"
+          defaultValue="Due"
          hiddenElements={['label']}
          onChange={(e) => setLastName(e.target.value)}
        />
```

## Stripe Appsひとりアドベントカレンダー 2022

今年ベータリリースされたばかりのStripe Appsは、まだ日本語の情報が多くありません。

そこでQiita Advent Calendar 2022にて、毎日Stripe Appsについての情報を投稿します。

https://qiita.com/advent-calendar/2022/stripe-apps

ノーコードで利用する方法や、開発するためのTipsなども紹介予定ですので、ぜひ購読をお願いします。