I'm using the urql
implementation to with graphql-sse to create a graphql client as follows:
import {
Client,
cacheExchange,
fetchExchange,
subscriptionExchange,
} from "urql";
import { KEYS, serverDomain } from "../constants";
import { del, retrieve } from "../utils";
import { createClient as createSSEClient } from "graphql-sse";
import { authExchange } from "@urql/exchange-auth";
import { getToken, setToken } from "../state/token";
const sseClient = createSSEClient({
url: `http://${serverDomain}/graphql`,
});
export const client = new Client({
url: `http://${serverDomain}/graphql`,
requestPolicy: "network-only",
exchanges: [
cacheExchange,
fetchExchange,
authExchange(async (utils) => {
const jwt = await retrieve(KEYS.TOKEN_KEY);
setToken(jwt);
return {
addAuthToOperation(operation) {
if (jwt) {
return utils.appendHeaders(operation, {
Authorization: `Bearer ${jwt}`,
});
}
return operation;
},
willAuthError(_operation) {
return !jwt;
},
didAuthError(error, _operation) {
return error.graphQLErrors.some(
(e) => e.extensions?.code === "FORBIDDEN"
);
},
async refreshAuth() {
setToken(null);
await del(KEYS.TOKEN_KEY);
},
};
}),
subscriptionExchange({
forwardSubscription(operation) {
return {
subscribe: (sink) => {
const dispose = sseClient.subscribe(operation as any, sink);
return {
unsubscribe: dispose,
};
},
};
},
}),
],
fetchOptions: () => {
const token = getToken();
return {
headers: { authorization: `Bearer ${token || ""}` },
};
},
});
Then when try to use the useSubscription
hook as follows to listen to new incoming subscriptions in my component as follows:
import { COLORS, FONTS } from "../../constants";
import { AppParamList } from "../../params";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import { HomeStack } from "./home";
import { FriendsStack } from "./friends";
import { NotificationsStack } from "./notifications";
import { SettingsStack } from "./settings";
import TabIcon from "../../components/TabIcon/TabIcon";
import {
MaterialCommunityIcons,
MaterialIcons,
Ionicons,
} from "@expo/vector-icons";
import { useMeStore } from "../../store";
import { useSubscription } from "urql";
const Tab = createBottomTabNavigator<AppParamList>();
const Doc = `
subscription OnNewFriendRequest($input: OnNewFriendRequestInputType!) {
onNewFriendRequest(input: $input) {
message
friend {
id
nickname
}
}
}
`;
export const AppTabs = () => {
const { me } = useMeStore();
const [{ data, fetching, error }] = useSubscription({
query: Doc,
variables: {
input: { id: "ef7c5256-80f0-4de0-9893-51f3e3e9926e" },
},
});
console.log(JSON.stringify({ data, fetching, error }, null, 2));
return (
<Tab.Navigator
initialRouteName="Home"
screenOptions={{
headerShown: false,
tabBarHideOnKeyboard: true,
tabBarStyle: {
elevation: 0,
shadowOpacity: 0,
borderTopWidth: 0,
borderColor: "transparent",
backgroundColor: COLORS.primary,
paddingVertical: 10,
height: 80,
width: "auto",
},
tabBarShowLabel: false,
tabBarBadgeStyle: {
backgroundColor: "cornflowerblue",
color: "white",
fontSize: 10,
maxHeight: 20,
maxWidth: 20,
marginLeft: 3,
},
tabBarVisibilityAnimationConfig: {
hide: {
animation: "timing",
},
show: {
animation: "spring",
},
},
tabBarItemStyle: {
width: "auto",
},
}}
>
<Tab.Screen
options={{
tabBarIcon: (props) => (
<TabIcon
{...props}
title="home"
Icon={{
name: "home-account",
IconComponent: MaterialCommunityIcons,
}}
/>
),
}}
name="Home"
component={HomeStack}
/>
<Tab.Screen
options={{
tabBarIcon: (props) => (
<TabIcon
{...props}
title="friends"
Icon={{
name: "person-search",
IconComponent: MaterialIcons,
}}
/>
),
}}
name="Friends"
component={FriendsStack}
/>
<Tab.Screen
options={{
tabBarIcon: (props) => (
<TabIcon
{...props}
title="notifications"
Icon={{
name: "notifications",
IconComponent: Ionicons,
}}
/>
),
}}
name="Notifications"
component={NotificationsStack}
/>
<Tab.Screen
options={{
tabBarIcon: (props) => (
<TabIcon
{...props}
title="settings"
Icon={{
name: "settings",
IconComponent: Ionicons,
}}
/>
),
}}
name="Settings"
component={SettingsStack}
/>
</Tab.Navigator>
);
};
In my logs in a react-native application i'm only getting the loading state to true
as follows:
But in my React web app when a new subscription is fired i'm getting the expected results as follows:
{
"data": {
"onNewFriendRequest": null
},
"fetching": false
}
Why am i getting this different behaviour in react-native?.