<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Patrik</title>
    <description>The latest articles on Forem by Patrik (@fedorish).</description>
    <link>https://forem.com/fedorish</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F939771%2Fb642fe51-74df-4750-93b5-4e0e117f062e.png</url>
      <title>Forem: Patrik</title>
      <link>https://forem.com/fedorish</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/fedorish"/>
    <language>en</language>
    <item>
      <title>React Native Offline First with TanStack Query</title>
      <dc:creator>Patrik</dc:creator>
      <pubDate>Sat, 03 Dec 2022 12:07:54 +0000</pubDate>
      <link>https://forem.com/fedorish/react-native-offline-first-with-tanstack-query-1pe5</link>
      <guid>https://forem.com/fedorish/react-native-offline-first-with-tanstack-query-1pe5</guid>
      <description>&lt;p&gt;It's very important to give your users a good in-app experience even if their app can't connect to the internet. In this post I will show you how to persist your API calls / mutations when the device is offline and keep your app and backend in sync by storing the mutations and retrigger when the device reconnects to the internet.&lt;/p&gt;

&lt;p&gt;For this &lt;a href="https://github.com/fedorish/example-react-native-offline-tanstack-query" rel="noopener noreferrer"&gt;example&lt;/a&gt; I'm using &lt;a href="https://supabase.com/" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt; as a backend to fetch and post data. If you need a backend and / or starter code you can follow their &lt;a href="https://supabase.com/docs/guides/with-expo" rel="noopener noreferrer"&gt;Expo Quickstart&lt;/a&gt; to create an application that's hooked up to a backend in just minutes. &lt;/p&gt;

&lt;p&gt;This post will be split into two sections, one where I will try and explain what you need to add to your own app to get it working. The other section will show you how to use the &lt;a href="https://github.com/fedorish/example-react-native-offline-tanstack-query" rel="noopener noreferrer"&gt;example app on GitHub&lt;/a&gt; I've provided. &lt;/p&gt;

&lt;h1&gt;
  
  
  Adding it to your existing app
&lt;/h1&gt;

&lt;p&gt;I would recommend that you look through my example on GitHub to see a working demo and that you read the documentation. I will not go into TanStack Query details such as how to query data.&lt;/p&gt;

&lt;p&gt;We'll start off with installing the packages we need.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing packages
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://tanstack.com/query/v4/docs/installation" rel="noopener noreferrer"&gt;Docs: TanStack Query&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i @tanstack/react-query
&lt;span class="c"&gt;# or&lt;/span&gt;
pnpm add @tanstack/react-query
&lt;span class="c"&gt;# or&lt;/span&gt;
yarn add @tanstack/react-query
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://tanstack.com/query/v4/docs/plugins/createAsyncStoragePersister" rel="noopener noreferrer"&gt;Docs: createAsyncStoragePersister&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @tanstack/query-async-storage-persister @tanstack/react-query-persist-client
&lt;span class="c"&gt;# or &lt;/span&gt;
pnpm add @tanstack/query-async-storage-persister @tanstack/react-query-persist-client
&lt;span class="c"&gt;# or&lt;/span&gt;
yarn add @tanstack/query-async-storage-persister @tanstack/react-query-persist-client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://docs.expo.dev/versions/latest/sdk/netinfo/" rel="noopener noreferrer"&gt;Docs: NetInfo&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx expo &lt;span class="nb"&gt;install&lt;/span&gt; @react-native-community/netinfo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://docs.expo.dev/versions/latest/sdk/async-storage/" rel="noopener noreferrer"&gt;Docs: AsyncStorage&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx expo &lt;span class="nb"&gt;install&lt;/span&gt; @react-native-async-storage/async-storage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are using Supabase you might have to use this polyfill and import it in &lt;code&gt;App.js&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i react-native-url-polyfill
&lt;span class="c"&gt;# or&lt;/span&gt;
yarn add react-native-url-polyfill
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Network status
&lt;/h3&gt;

&lt;p&gt;First thing we'll add is an &lt;code&gt;EventListener&lt;/code&gt; that listens to network changes. In the browser TanStack Query handles this automatically, but on mobile we need to set it up ourselves. If you are running this on an iPhone simulator you might experience issues, &lt;em&gt;it seems like the iPhone simulators have some issues reconnecting properly. I have not experience this with Android simulators.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Platform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OS&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;web&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NetInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
          &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isConnected&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
          &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isConnected&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
          &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isInternetReachable&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;onlineManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setOnline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  QueryClientProvider
&lt;/h3&gt;

&lt;p&gt;Instead of using the normal &lt;code&gt;QueryClientProvider&lt;/code&gt; we will use &lt;code&gt;PersistQueryClientProvider&lt;/code&gt;. The configuration we will use is the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queryClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;QueryClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
   &lt;span class="na"&gt;defaultOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;mutations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;staleTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;Infinity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;cacheTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;Infinity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;asyncPersist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createAsyncStoragePersister&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AsyncStorage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;throttleTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need to configure mutationDefaults which will run when the mutations we specify are triggered.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;  &lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setMutationDefaults&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yourKey&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// mutationFn will give you access to&lt;/span&gt;
    &lt;span class="c1"&gt;// any variables passed to the mutation&lt;/span&gt;
    &lt;span class="na"&gt;mutationFn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;variable_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;variable_2&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Your API call (should return a promise)&lt;/span&gt;
    &lt;span class="c1"&gt;// return axios.post('/user', {&lt;/span&gt;
    &lt;span class="c1"&gt;//          firstName: 'Fred',&lt;/span&gt;
    &lt;span class="c1"&gt;//          lastName: 'Flintstone'&lt;/span&gt;
    &lt;span class="c1"&gt;//     });&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finishing up your &lt;code&gt;App.js&lt;/code&gt; should return something similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PersistQueryClientProvider&lt;/span&gt;
      &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;persistOptions&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;persister&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;asyncPersist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="c1"&gt;// onSuccess will be called when the initial restore is finished&lt;/span&gt;
      &lt;span class="c1"&gt;// resumePausedMutations will trigger any paused mutations&lt;/span&gt;
      &lt;span class="c1"&gt;// that was initially triggered when the device was offline&lt;/span&gt;
      &lt;span class="na"&gt;onSuccess&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resumePausedMutations&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;YourApp&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;PersistQueryClientProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should be enough to get up and running, but depending on your project you might have to update certain options to work in your app. &lt;/p&gt;

&lt;h1&gt;
  
  
  Example using Supabase
&lt;/h1&gt;

&lt;p&gt;Sometimes it can helpful to play around with a working example yourself. I've setup basic example that you can play around with. You can find the &lt;a href="https://github.com/fedorish/example-react-native-offline-tanstack-query" rel="noopener noreferrer"&gt;repo on github&lt;/a&gt; and for this to work you will need to setup a &lt;a href="https://supabase.com/" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt; project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a project
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="//app.supabase.com"&gt;app.supabase.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Sign in or Sign up if you haven't already&lt;/li&gt;
&lt;li&gt;Click on "New Project".&lt;/li&gt;
&lt;li&gt;Enter your project details.&lt;/li&gt;
&lt;li&gt;Wait for the new database to launch.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Database
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to the &lt;a href="https://app.supabase.com/project/_/sql" rel="noopener noreferrer"&gt;SQL Editor&lt;/a&gt; page in the Dashboard.&lt;/li&gt;
&lt;li&gt;Click &lt;code&gt;New query&lt;/code&gt; and paste and run the SQL below.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;create&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="n"&gt;todos&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;bigint&lt;/span&gt; &lt;span class="k"&gt;generated&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="k"&gt;identity&lt;/span&gt; &lt;span class="k"&gt;primary&lt;/span&gt; &lt;span class="k"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;inserted_at&lt;/span&gt; &lt;span class="nb"&gt;timestamp&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt; &lt;span class="k"&gt;zone&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="n"&gt;timezone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'utc'&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;updated_at&lt;/span&gt; &lt;span class="nb"&gt;timestamp&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt; &lt;span class="k"&gt;zone&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="n"&gt;timezone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'utc'&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;todo&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add API Keys
&lt;/h3&gt;

&lt;p&gt;Before we can run the application we need to connect our app to the Supabase project by adding our projects &lt;code&gt;Reference ID&lt;/code&gt; and &lt;code&gt;anon&lt;/code&gt;-key to &lt;code&gt;Supabase.js&lt;/code&gt;. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the &lt;a href="https://app.supabase.com/project/_/settings" rel="noopener noreferrer"&gt;Settings&lt;/a&gt; page in the Dashboard.&lt;/li&gt;
&lt;li&gt;Under &lt;code&gt;General&lt;/code&gt; you will find your &lt;code&gt;Reference ID&lt;/code&gt; (you can also see it in your browsers URL). In  &lt;code&gt;Supabase.js&lt;/code&gt; replace &lt;code&gt;&amp;lt;project-reference-id&amp;gt;&lt;/code&gt; with your own &lt;code&gt;ID&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Go to the &lt;a href="https://app.supabase.com/project/_/settings/api" rel="noopener noreferrer"&gt;Settings -&amp;gt; API&lt;/a&gt; page and add your &lt;code&gt;anon&lt;/code&gt;-key to the &lt;code&gt;supabaseAnonKey&lt;/code&gt;-variable &lt;code&gt;Supabase.js&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now you are ready to launch the app and test it out. I've had some issues with both Android and iPhone simulators, such as not reconnecting to internet correctly and not persisting mutations correctly. So I would recommend testing this on a physical device. &lt;/p&gt;

&lt;p&gt;Hopefully this helps someone, let me know if you have any questions or find any errors I've made.&lt;/p&gt;

</description>
      <category>html</category>
      <category>ui</category>
      <category>learning</category>
    </item>
    <item>
      <title>Google Sign-In using Supabase and React Native (Expo)</title>
      <dc:creator>Patrik</dc:creator>
      <pubDate>Wed, 02 Nov 2022 20:13:05 +0000</pubDate>
      <link>https://forem.com/fedorish/google-sign-in-using-supabase-and-react-native-expo-14jf</link>
      <guid>https://forem.com/fedorish/google-sign-in-using-supabase-and-react-native-expo-14jf</guid>
      <description>&lt;p&gt;This post will cover how to add Google Sign-In to your &lt;a href="//expo.dev"&gt;Expo&lt;/a&gt; + &lt;a href="https://supabase.com/" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt; project using &lt;code&gt;expo-auth-session&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Disclaimer: It seems like this does not work with Expo SDK 48 as of now, but should still work versions below (I'm still on 47). Keep an eye on &lt;a href="https://github.com/supabase/gotrue-js/issues/406" rel="noopener noreferrer"&gt;this GitHub Issue&lt;/a&gt; where other people have mentioned the problem.&lt;/p&gt;

&lt;p&gt;If you don't have a Expo + Supabase project  you can follow this &lt;a href="https://supabase.com/docs/guides/with-expo" rel="noopener noreferrer"&gt;supabase guide&lt;/a&gt;. This example uses v2 of &lt;code&gt;supabase-js&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;We'll start of by configuring Supabase and Google Cloud&lt;/p&gt;

&lt;h2&gt;
  
  
  Google Cloud
&lt;/h2&gt;

&lt;p&gt;Go to &lt;a href="https://console.cloud.google.com/" rel="noopener noreferrer"&gt;Google Cloud&lt;/a&gt; and create a new project if you haven't done so. When you have your Google Cloud Project setup go to the &lt;a href="https://console.cloud.google.com/apis/credentials" rel="noopener noreferrer"&gt;Credentials page&lt;/a&gt;. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If you see a prompt to "Configure Consent Screen", click that button and follow the instructions to finish the setup. &lt;/li&gt;
&lt;li&gt;Click on "Create Credentials" that should be located at the top of the screen and select "OAuth Client ID". &lt;/li&gt;
&lt;li&gt;In the "Application type" field select "Web application" and give your application a name.&lt;/li&gt;
&lt;li&gt;Under "Authorized redirect URIs" add &lt;code&gt;https://{YOUR_PROJECT_REFERENCE_ID}.supabase.co/auth/v1/callback&lt;/code&gt;. Your reference ID can be found under &lt;code&gt;Settings -&amp;gt; General&lt;/code&gt; in your Supabase project dashboard, click &lt;code&gt;SAVE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click on your newly created credential under &lt;code&gt;OAuth 2.0 Client IDs&lt;/code&gt;, in the top right you should see &lt;code&gt;Client ID&lt;/code&gt; and &lt;code&gt;Client secret&lt;/code&gt;. Copy and save these because they will be needed when we configure Supabase. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdpdq8nv527mp82kqj9q8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdpdq8nv527mp82kqj9q8.png" alt="Google Cloud"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Supabase
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Activate Google Provider
&lt;/h3&gt;

&lt;p&gt;In your Supabase project dashbarod go to &lt;code&gt;Authentication -&amp;gt; Providers&lt;/code&gt; &lt;br&gt;
&lt;code&gt;https://app.supabase.com/project/{YOUR_PROJECT_REFERENCE_ID}/auth/providers&lt;/code&gt;. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scroll down to &lt;code&gt;Google&lt;/code&gt; and open it. &lt;/li&gt;
&lt;li&gt;Add the &lt;code&gt;Client ID&lt;/code&gt; and &lt;code&gt;Client Secret&lt;/code&gt; you saved from step 5 in configuring Google Cloud. &lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;Save&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now the Google provider should be configured in your Supabase project. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fid4fy16x0yelw5wymaoa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fid4fy16x0yelw5wymaoa.png" alt="Google Provider"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Add Redirect
&lt;/h3&gt;

&lt;p&gt;Go to your Supabase project and navigate to &lt;code&gt;Authentication -&amp;gt; URL Configuration&lt;/code&gt; &lt;br&gt;
&lt;code&gt;https://app.supabase.com/project/{YOUR_PROJECT_REFERENCE_ID}/auth/url-configuration&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Click on &lt;code&gt;Add URL&lt;/code&gt; and add &lt;code&gt;exp://{LOCAL_IP_ADDRESS}:19000/--/auth/callback&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Mine looks like&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuwpttlsyx61r8l8esctt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuwpttlsyx61r8l8esctt.png" alt="Supabase Redirect URL"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Now we are done configuring Supabase. &lt;/p&gt;

&lt;h3&gt;
  
  
  Code
&lt;/h3&gt;

&lt;p&gt;If you followed the &lt;a href="https://supabase.com/docs/guides/with-expo" rel="noopener noreferrer"&gt;supabase guide&lt;/a&gt; you should be pretty much good to go. We need to create a new functions to handle the Google Sign-In. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;makeRedirectUri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;startAsync&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;expo-auth-session&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;supabaseUrl&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./supabase&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;googleSignIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// This will create a redirectUri&lt;/span&gt;
  &lt;span class="c1"&gt;// This should be the URL you added to "Redirect URLs" in Supabase URL Configuration&lt;/span&gt;
  &lt;span class="c1"&gt;// If they are different add the value of redirectUrl to your Supabase Redirect URLs&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;redirectUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;makeRedirectUri&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/auth/callback&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// authUrl: https://{YOUR_PROJECT_REFERENCE_ID}.supabase.co&lt;/span&gt;
  &lt;span class="c1"&gt;// returnURL: the redirectUrl you created above.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;startAsync&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;authUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;supabaseUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/auth/v1/authorize?provider=google&amp;amp;redirect_to=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;redirectUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;returnUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;redirectUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// If the user successfully signs in&lt;/span&gt;
  &lt;span class="c1"&gt;// we will have access to an accessToken and an refreshToken&lt;/span&gt;
  &lt;span class="c1"&gt;// and then we'll use setSession (https://supabase.com/docs/reference/javascript/auth-setsession)&lt;/span&gt;
  &lt;span class="c1"&gt;// to create a Supabase-session using these token&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setSession&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;authResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;refresh_token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;authResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;refresh_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now you should be all good to go! Call this function when a user wants to sign in with Google. &lt;/p&gt;

&lt;p&gt;You might need to add the following import to your &lt;code&gt;App.tsx&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="nb"&gt;global&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;buffer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Or (depending on your preference / project)&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;buffer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;global&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Credit to &lt;a href="https://dev.to/daliboru/comment/23m3i"&gt;Dalibor Belic&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's it! Leave a comment if you find any errors or if you have any questions.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I want to give credit to the people in this &lt;a href="https://github.com/supabase/gotrue-js/issues/406" rel="noopener noreferrer"&gt;GitHub Issue&lt;/a&gt; whose comments helped me put all the pieces together.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>supabase</category>
      <category>reactnative</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
