[Stripe Updates] Stripe Elementで、ReadOnlyモードが実装されました

Stripe ElementのAPIがアップデートされ、「決済フォームをReadOnlyモードに設定する」オプションが追加されました。


## コードサンプル

実装方法はとても簡単で、`elements.create`の第二引数に`readOnly: true`を設定するだけです。

```html
<script src="https://js.stripe.com/v3/"></script>
<!-- 中略 -->
<div id="payment-element"></div>
<script>
const stripe = Stripe('pk_test_YOUR_STRIPE_PUBLISHABLE_API_KEY')
const elements = stripe.elements({
    appearance: {
        theme: 'stripe'
    },
    clientSecret: 'pi_YOUR_PAYMENT_INTENT'
});
const paymentElement = elements.create('payment', {
    readOnly: true
});
paymentElement.mount("#payment-element");
</script>
```

これにより、`element.create().mount()`で生成された入力フィールドに`readonly`属性が追加されます。

![スクリーンショット 0003-12-15 12.08.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/d0cb33b5-0b1e-dfd8-45ba-e722733a52b6.png)

## `element.update()`での切り替えも可能

`update`で`readOnly`のステータスを変更することもできます。
以下のコードでは、`Disable` / `Enable`それぞれのボタンを押すことで、`readOnly`にするかしないかのステータスを変更できます。

```html
<script src="https://js.stripe.com/v3/"></script>
<!-- 中略 -->
<button onclick="handleDisable()">Disable</button>
<button onclick="handleEnable()">Enable</button>
<div id="payment-element"></div>
<script>
// ...一部省略
const paymentElement = elements.create('payment', {
    readOnly: true
});
paymentElement.mount("#payment-element")

function handleDisable() {
    paymentElement.update({
        readOnly: true
    })
}
function handleEnable() {
    paymentElement.update({
        readOnly: false
    })
}
</script>
```

## ユースケース
### 特定の条件を満たした場合のみ、カード情報を入力させたい

配送先などの顧客情報が入力された状態になってから、カード情報を入力させるUIを設計したい場合に`readOnly`が利用できます。
以下のサンプルでは、`name`が空の場合はカード情報が入力できない（readOnly）状態になります。

```jsx
import { loadStripe } from "@stripe/stripe-js";
import { Elements, PaymentElement, useElements, useStripe } from "@stripe/react-stripe-js";
import { useEffect, useState } from 'react';
const stripePromise = loadStripe(process.env.STRIPE_PUBLISHABLE_API_KEY);
// 中略
const Payment = () => {
  const [isReadOnly, setIsReadOnly] = useState<boolean>(false);
  const [name, setName] = useState('')
  useEffect(() => {
    setIsReadOnly(!name)
  }, [setIsReadOnly,name])
  return (
      <input value={name} onChange={e => {
        setName(e.target.value)
      }} />
      <PaymentElement id="payment-element" options={{
        readOnly: isReadOnly,
      }} />
  )
}

const Home = () => {
  const options = {
    appearance:{
      theme: 'stripe',
    },
    clientSecret,
  }
  return (
    <Elements stripe={stripePromise} options={options}>
      <Payment />
    </Elements>
  )
}
```

### 処理中に入力内容を変更させたくない場合

サービスによっては、Submit時の処理にすこし時間がかかる場合があります。そしてその処理が終わるまでの間、フォームの内容を変更させたくないケースもあります。

その場合、処理が実行中は`readOnly: true`をセットして、内容の変更をブロックすることができます。

```jsx
import { loadStripe } from "@stripe/stripe-js";
import { Elements, PaymentElement, useElements, useStripe } from "@stripe/react-stripe-js";
import { useEffect, useState } from 'react';
const stripePromise = loadStripe(process.env.STRIPE_PUBLISHABLE_API_KEY);
// 中略

const Payment: FC = () => {
  const [isReadOnly, setIsReadOnly] = useState<boolean>(false);

  const stripe = useStripe();
  const elements = useElements();
  return (
    <form onSubmit={async e => {
      e.preventDefault()
      if (!elements || !stripe) return;

      // 処理開始と同時に、変更できなくする
      setIsReadOnly(true)
      const { error } = await stripe.confirmPayment({
        elements,
        confirmParams: {
          return_url: 'http://localhost:3000'
        }
      })

      // エラーが返ってきた場合、再入力可能にする
      if (error) {
        alert(error.message)
        setIsReadOnly(false)
        return;
      }
　　　　　　　　　　　　// 時間のかかる処理の例
      await new Promise(resolve => {
        setTimeout(() => {
          resolve(true)
        }, 10000)
      })

      // 処理が完了したので、変更可能にする
      setIsReadOnly(false)
    }}>
      <PaymentElement id="payment-element" options={{
        readOnly: isReadOnly,
      }} />
      <button type="submit">Submit</button>
    </form>
  )
}
```

## 参考資料
- [https://stripe.com/docs/js/elements_object/create_payment_element#payment_element_create-options-readOnly](https://stripe.com/docs/js/elements_object/create_payment_element#payment_element_create-options-readOnly?utm_source=qiita&utm_medium=stripeUpdates)
- [https://stripe.com/docs/js/elements_object/update_payment_element#payment_element_update-options-readOnly](https://stripe.com/docs/js/elements_object/update_payment_element#payment_element_update-options-readOnly?utm_source=qiita&utm_medium=stripeUpdates)

# [PR] Stripe開発者向け情報をQiitaにて配信中！
2021年12月よりQiitaにて、Stripe開発者のためのブログ記事更新を開始しました。

- [Stripe Updates]：開発者向けStripeアップデート紹介・解説
- ユースケース別のStripe製品や実装サンプルの紹介
- Stripeと外部サービス・OSSとの連携方法やTipsの紹介
- 初心者向けのチュートリアル(予定)

など、Stripeを利用してオンラインビジネスを始める方法について随時更新してまいります。

-> [Stripe Organizationsをフォローして最新情報をQiitaで受け取る](https://qiita.com/organizations/stripe)