DEV Community

Spencer Carli
Spencer Carli

Posted on • Originally published at reactnativeschool.com

How to Share from a React Native App (including the Web)

React Native's web support continues to get better and better, especially if you're using Expo. With Expo it just works out of the box.

But adding another supported platform to your app adds complexity! You've got to make sure things work on each supported platform.

Recently I was building a game with React Native, Match the Pairs, that allows a user to share how many moves it took them to beat the game.

It runs on iOS, Android, and the web. React Native's Share API works on iOS and Android but not the web so I had to come up with a solution to handle this.

Today we'll cover how to build a function that has differing functionality depending on what platform it runs on.

The shareGame Function

First we'll create the function that will be called when a user presses "Share game" in the app.

Screenshots of match the pair on iOS, Android, and the web

type shareGameProps = {
  emojis: string[]
  moveCount: number
}

export const shareGame = async ({ emojis, moveCount }: shareGameProps) => {}
Enter fullscreen mode Exit fullscreen mode

Example input:

shareGame({
  emojis: [
    "🏄",
    "💣",
    "📬",
    "😇",
    "🤠",
    "🦦",
    "📸",
    "📬",
    "🤠",
    "🏄",
    "🌮",
    "🌮",
    "💣",
    "😇",
    "🦦",
    "📸",
  ],
  moveCount: 16,
})
Enter fullscreen mode Exit fullscreen mode

The Share API

First we can take advantage of the Share API from React Native.

import { Share } from "react-native"

type shareGameProps = {
  emojis: string[]
  moveCount: number
}

export const shareGame = async ({ emojis, moveCount }: shareGameProps) => {
  const message = "This is an example message"

  return await Share.share({
    message,
  })
}
Enter fullscreen mode Exit fullscreen mode

On iOS and Android this works great but the web throws an error that it isn't supported.

Share dialogs on iOS and Android and an error message on the web

Leveraging the Platform API

So, what can we do about this differing API support between platforms?

We can leverage the core Platform API to change the functionality on a given platform.

import { Share, Platform } from "react-native"
import * as Clipboard from "expo-clipboard"

type shareGameProps = {
  emojis: string[]
  moveCount: number
}

export const shareGame = async ({ emojis, moveCount }: shareGameProps) => {
  const message = "This is an example message"

  if (Platform.OS === "web") {
    await Clipboard.setStringAsync(message)

    alert(`The following message was copied to your clipboard.\n\n${message}`)
    return
  }

  return await Share.share({
    message,
  })
}
Enter fullscreen mode Exit fullscreen mode

Above you can see that if the platform is "web" we'll copy the message to their clipboard (via expo-clipboard or react-native-clipboard).

We're also using alert to notify the user that we copied the message to the clipboard and what the actual message was. A custom modal would be an even better solution here.

If the platform isn't "web" then we'll continue on to use the Share API.

The web version of the app alerting that something has been copied to the clipboard

Bonus: Building the Share Message

This section isn't really pertinent to the content of this article but I figured I'd add it in. Let's create the actual message.

We want to create the grid of emojis that the user played, like this:

🏄 💣 📬 😇
🤠 🦦 📸 📬
🤠 🏄 🌮 🌮
💣 😇 🦦 📸
Enter fullscreen mode Exit fullscreen mode

To do so we'll split our array of emojis into 4 rows of 4 emojis and then join them with a new line character.

import { Share, Platform } from "react-native"
import * as Clipboard from "expo-clipboard"

type shareGameProps = {
  emojis: string[]
  moveCount: number
}

const buildRow = (emojis: string[], start: number, end: number) =>
  emojis.slice(start, end).join(" ")

export const shareGame = async ({ emojis, moveCount }: shareGameProps) => {
  const row1 = buildRow(emojis, 0, 4)
  const row2 = buildRow(emojis, 4, 8)
  const row3 = buildRow(emojis, 8, 12)
  const row4 = buildRow(emojis, 12, 16)

  const emojiBoard = [row1, row2, row3, row4].join("\n")
  const message = `I just beat Match the pairs in ${moveCount} moves!\n${emojiBoard}`

  if (Platform.OS === "web") {
    await Clipboard.setStringAsync(message)

    alert(`The following message was copied to your clipboard. \n\n${message}`)
    return
  }

  return await Share.share({
    message,
  })
}
Enter fullscreen mode Exit fullscreen mode

And there we have it! A function to share the game result that works across multiple platforms, even when the same APIs aren't supported on each platform.

iOS, Android, and the web showing their respective version of the share dialog

Top comments (0)