-
Notifications
You must be signed in to change notification settings - Fork 471
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
not working react native web #1096
Comments
Got the exact same issue. |
Got the exact same issue. Using: |
Here's a workaround if you are using something like Zustand: // Zustand Store
{
...,
storage: createJSONStorage(() =>
Platform.OS === "web" ? localStorage : AsyncStorage
),
...,
} |
localStorage ? |
For those using supabase and seeing this in the stack trace too, check out supabase/supabase-js#786 |
@adsalihac At least, Zustand is able to deal with that seamlessly. |
i am using redux with presist , it is support ? @t1gu1 , also what about Zustand , it is better than redux ? |
@adsalihac Nope Redux is more complexe on that side. We migrate all our project to use Zustand cause it's stupid easy to use and works really well! |
what about state migration in zustand (like version update) , which zustand is using , official module right ? it is possible to get data like this (store.getState()?.auth?.user) ? |
@adsalihac Yes and yes. |
Thank you @t1gu1 |
I think I encountered the same problem. Using: ios error message [ReferenceError: Can't find variable: localStorage] |
Upgrade Expo package: (Just to be sure)
Where you create your Zustand store, simply add that for the storage: Use |
Confirmed the same issue
|
For me it seems like this issue can be close. |
some issue here with 2.0.0 version |
I'm having the same issue... Latest expo sdk and react-native-async-storage version |
Great! I solve it by the following code. import { AppState, Platform } from 'react-native';
import 'react-native-url-polyfill/auto';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = process.env.EXPO_PUBLIC_SUPABASE_URL;
const supabaseAnonKey = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY;
if (!supabaseUrl || !supabaseAnonKey) {
throw new Error('Supabase URL or Anon Key is not defined');
}
class SupabaseStorage {
async getItem(key: string) {
if (Platform.OS === "web") {
if (typeof localStorage === "undefined") {
return null;
}
return localStorage.getItem(key);
}
return AsyncStorage.getItem(key);
}
async removeItem(key: string) {
if (Platform.OS === "web") {
return localStorage.removeItem(key);
}
return AsyncStorage.removeItem(key);
}
async setItem(key: string, value: string) {
if (Platform.OS === "web") {
return localStorage.setItem(key, value);
}
return AsyncStorage.setItem(key, value);
}
}
export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
auth: {
storage: new SupabaseStorage(),
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: false,
},
}); |
Window cannot be used, otherwise localstorage |
Just wanted to chime in that I was able to use this package on the web without needing to make any modifications :) |
This is an issue for us. This seems to be one of the few storage solutions for expo that should work with Web. I hope this gets resolved |
I suspect the connection between expo-router, node, and localStorage is more nuanced than that, as expo-notifications does not advertise support for web. The fix in the above comment and the merged fix for that particular expo-notifications on web issue both utilize: if (typeof localStorage === 'undefined') {
return null;
} I am using expo-router and supabase for a universal app with secure storage across platforms. My solution, inspired by #1096 (comment), uses platform specific extensions (just as your referenced comment suggested for their temporary fix), and to my knowledge it is working as needed: // /utils/supabase/storage.native.ts
import AsyncStorage from '@react-native-async-storage/async-storage';
import * as aesjs from 'aes-js';
import * as SecureStore from 'expo-secure-store';
// As Expo's SecureStore does not support values larger than 2048
// bytes, an AES-256 key is generated and stored in SecureStore, while
// it is used to encrypt/decrypt values stored in AsyncStorage.
export class Storage {
private async _encrypt(key: string, value: string) {
const encryptionKey = crypto.getRandomValues(new Uint8Array(256 / 8));
const cipher = new aesjs.ModeOfOperation.ctr(encryptionKey, new aesjs.Counter(1));
const encryptedBytes = cipher.encrypt(aesjs.utils.utf8.toBytes(value));
await SecureStore.setItemAsync(key, aesjs.utils.hex.fromBytes(encryptionKey));
return aesjs.utils.hex.fromBytes(encryptedBytes);
}
private async _decrypt(key: string, value: string) {
const encryptionKeyHex = await SecureStore.getItemAsync(key);
if (!encryptionKeyHex) {
return encryptionKeyHex;
}
const cipher = new aesjs.ModeOfOperation.ctr(
aesjs.utils.hex.toBytes(encryptionKeyHex),
new aesjs.Counter(1)
);
const decryptedBytes = cipher.decrypt(aesjs.utils.hex.toBytes(value));
return aesjs.utils.utf8.fromBytes(decryptedBytes);
}
async setItem(key: string, value: string) {
const encrypted = await this._encrypt(key, value);
await AsyncStorage.setItem(key, encrypted);
}
async getItem(key: string) {
const encrypted = await AsyncStorage.getItem(key);
if (!encrypted) return encrypted;
return await this._decrypt(key, encrypted);
}
async removeItem(key: string) {
await AsyncStorage.removeItem(key);
await SecureStore.deleteItemAsync(key);
}
} // /utils/supabase/storage.ts
import secureLocalStorage from 'react-secure-storage';
export class Storage {
async setItem(key: string, value: string) {
secureLocalStorage.setItem(key, value);
}
async getItem(key: string) {
return secureLocalStorage.getItem(key) as string | null;
}
async removeItem(key: string) {
secureLocalStorage.removeItem(key);
secureLocalStorage.clear();
}
} // /utils/supabase/index.ts
import 'react-native-url-polyfill/auto';
import { createClient } from '@supabase/supabase-js';
import { AppState } from 'react-native';
import { Storage } from './storage';
import 'react-native-get-random-values';
const supabaseUrl = process.env.EXPO_PUBLIC_SUPABASE_URL!;
const supabaseAnonKey = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY!;
if (!supabaseUrl || !supabaseAnonKey) {
throw new Error('Supabase URL or Anon Key is not defined');
}
export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
auth: {
storage: new Storage(),
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: false,
},
});
// Tells Supabase Auth to continuously refresh the session automatically
// if the app is in the foreground. When this is added, you will continue
// to receive `onAuthStateChange` events with the `TOKEN_REFRESHED` or
// `SIGNED_OUT` event if the user's session is terminated. This should
// only be registered once.
AppState.addEventListener('change', (state) => {
if (state === 'active') {
supabase.auth.startAutoRefresh();
} else {
supabase.auth.stopAutoRefresh();
}
}); Prior to implementing a secure store, I recall localStorage working with a similar Platform evaluation. I hope this is useful to someone. If anyone thinks it's overkill, I'm open to feedback. 😉 |
Change the 'output' of the web node in 'app. json' from 'static' to 'single' |
Yes! This worked. Thank you for the tip! |
What happened?
Getting Error
Version
1.23.1
What platforms are you seeing this issue on?
System Information
Steps to Reproduce
The text was updated successfully, but these errors were encountered: