Hyoban

Hyoban

Don’t do what you should do, do you want.
x
github
email
telegram
follow

Re: React Nativeのゼロからの旅(パート1)

RN を書く理由#

1 つは、自分自身がまだ本格的に RN を書いたことがなく、その体験を試してみたいと思ったからです。最近、RSS リーダーの Follow に興味を持っていますが、まだモバイル版がないため、学習と実践の対象として利用できます。また、最近仕事を始めたので、仕事の後に自分の書きたいコードを書くモチベーションがなかなか湧かないので、目標を持つことで集中しやすくなります。

同時に、学習と開発のプロセスを週ごとに更新する小さなブログを書くことにしましたので、皆さんのご注目をお願いします。

準備#

hello world#

さて、言葉を多くする前に、最初のアプリを実行しましょう。ただし、「仕事を上手にするためには、まず道具を整える必要がある」ということわざがありますので、まず環境を整えましょう。

一般的には、Xcode をインストールするだけで十分ですが、私のように最近 macOS のベータ版にアップグレードした場合は、少し手間がかかります。

  1. App Store でダウンロードした Xcode は開けません。システムバージョンと一致しません。
  2. ダウンロードした Xcode ベータ版は直接開けません。the plug-in or one of its prerequisite plug-ins may be missing or damaged and may need to be reinstalled.というエラーメッセージが表示されるため、Xcode.app/Contents/Resources/Packages/内のインストールパッケージを手動でインストールする必要があります。参照:https://forums.developer.apple.com/forums/thread/660860
  3. コマンドラインで使用するベータ版 Xcode を選択する必要があります。xcode-select -s /Applications/Xcode-beta.app

次に、素晴らしいスケルトンが必要です。私は RN の技術スタックに詳しくないので、State of React Nativeを読んだ後、Twitter で見つけたCreate Expo Stackを選びました。

これは Expo プロジェクトのスケルトンとしてだけでなく、さまざまな主要な技術スタックの組み合わせオプションも提供してくれますので、アプリの作成を早く始めるのに非常に便利です。最終的に私が選んだ組み合わせは次のとおりです。

npx create-expo-stack@latest follow-app --expo-router --tabs --tamagui --pnpm --eas

ダークモードの処理#

スケルトンはデフォルトでライトモードのみをサポートしていますが、私は完璧主義者なので、それは受け入れられません。まずはそれを処理しましょう。このissueを参考に、Expo の設定を変更する必要があります。

{
  "expo": {
    "userInterfaceStyle": "automatic",
    "ios": {
      "userInterfaceStyle": "automatic"
    },
    "android": {
      "userInterfaceStyle": "automatic"
    }
  }
}

これでuseColorSchemeを使用してユーザーが選択したテーマモードを正常に取得できるようになります。ただし、この設定を変更した後は、expo prebuildを再度実行する必要があることに注意してください。これにより、Info.plist ファイルのUIUserInterfaceStyleキーの値がAutomaticに設定されます。

本番開始#

さて、それでは Follow アプリを書いてみましょう!

ログインアカウント#

Expo のドキュメントには詳細なAuthentication の統合ドキュメントがありますが、私たちはそれを使用する必要はありません。Follow の Web 版は既に処理されているため、私たちは単に Web 版のログインを呼び出し、アプリにログイン後にリダイレクトされるスキームリンクを処理する必要があります。

まず、アプリのスキームを設定し、アプリの設定でscheme: 'follow'を設定し、expo prebuildを実行します。

expo-web-browserを使用して Follow のログインページを開きます:

await WebBrowser.openBrowserAsync('https://dev.follow.is/login')

次に、expo-linkingを使用して URL のリスニングイベントを登録し、ログインウェブページからの URL 情報を受け取った後、その中のトークンを解析します。

Linking.addEventListener('url', ({ url }) => {
  const { hostname, queryParams } = Linking.parse(url)
  if (hostname === 'auth' && queryParams !== null && typeof queryParams.token === 'string') {
    WebBrowser.dismissBrowser()
    if (Platform.OS !== 'web') {
      SecureStore.setItemAsync(SECURE_AUTH_TOKEN_KEY, queryParams.token)
    }
  }
})

ここで遭遇した別の問題は、iPhone の Safari で非同期関数内のwindow.openが機能しないことです。target="_top"のパラメータを追加する必要があります。参考:https://stackoverflow.com/q/20696041/15548365

URL が auth ページにジャンプするため、ホームページにジャンプするためのルートapp/auth.tsxを追加できます。

import { router } from 'expo-router'

export default function Auth() {
  router.navigate('/')
  return null
}

OK、これでユーザーの認証トークンを取得できるようになりました。API を呼び出してみて、動作を確認してみましょう。

ユーザー情報の取得#

RN では、Web と同様にネットワークリクエストを行うことができますので、お好きなライブラリを使用することができます。

function useSession() {
  return useSWR(URL_TO_FOLLOW_SERVER, async (url) => {
    const authToken = await SecureStore.getItemAsync(SECURE_AUTH_TOKEN_KEY)
    const response = await fetch(url, {
      headers: {
        cookie: `authjs.session-token=${authToken}`,
      },
      credentials: 'omit',
    })
    const data = (await response.json()) as Session
    return data
  })
}

ここで、少し異常な設定を行っていますが、それは RN でのクッキーベースの認証にはいくつかの既知の問題があるためです。credentials: 'omit'を設定しない場合、2 回目のリクエストで正しくないクッキーが設定され、リクエストが失敗する可能性があります。これは、https://github.com/facebook/react-native/issues/23185#issuecomment-1148130842 を参考にしました。

データがあれば、ページをレンダリングすることができます。まずは簡単に書いてみましょう。

export default function UserInfo() {
  const { data: session, mutate } = useSession()

  return (
    <YStack flex={1} padding={20}>
      {session ? (
        <YStack>
          <XStack gap={24} alignItems="center">
            <Image
              source={{
                uri: session.user.image,
                height: 100,
                width: 100,
              }}
              borderRadius={50}
            />
            <YStack gap={8}>
              <Text color="$color12" fontSize="$8" fontWeight="600">
                {session.user.name}
              </Text>
              <Text color="$color12" fontSize="$5">
                {session.user.email}
              </Text>
            </YStack>
          </XStack>
        </YStack>
      ) : (
        <Button onPress={handlePressButtonAsync}>Login</Button>
      )}
    </YStack>
  )
}

さて、今の効果を見てみましょう。

あらら、Follow の Web 版はまだモバイルに適応していないようです。また PR を送れるぞ。

まとめ#

やっと動くソフトウェアができました。来週は何をしましょうか?おそらくアプリにデータベースを設定することでしょうか?アプリを書く場合、弱いネットワークやネットワークのない環境でも正常にフィードを閲覧できることを望んでいます。皆さんのアイデアについてお話ししましょう。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。