react-apollo
react-apollo copied to clipboard
TypeError: Cannot read property 'data' of undefined at MutationData.onMutationCompleted (react-hooks.cjs.js:654)
Intended outcome:
Hello, I have a React Native app but I cannot let my Mutation work even though it seems I have configured Apollo Client properly. Here is the relevant code of SignIn.tsx
//...other code...
const MUTATION_SIGN_IN = gql`
mutation userSignIn($input: SignInInput!) {
userSignIn(input: $input) {
authHeaders {
accessToken
client
expiry
tokenType
uid
}
user {
id
}
}
}
`;
//...other code...
const [formModel, setFormModel] = useState({
email: '',
password: ''
});
const [validationErrors, setValidationErrors] = useState({
login: false,
forgotPassword: false
});
const [userSignIn, {data, loading: signInLoading}] = useMutation(
MUTATION_SIGN_IN
);
const onLoginPress = () => {
userSignIn({
variables: {
input: {
email: {
...formModel
}
}
}
})
.then(({data: res, errors}) => {
// Execution never goes here
console.log(res);
console.log(errors);
setValidationErrors((prev) => ({...prev, login: !!errors}));
})
.catch((reason) => {
// But always goes here with the error specified below
console.log(reason);
setValidationErrors((prev) => ({...prev, login: !!reason}));
});
};
//...other code till the relative part of jsx which is the button...
<Button
mode="contained"
loading={signInLoading}
disabled={formModelEmpty()}
onPress={onLoginPress}>
{translations.SIGNIN_LOGIN_BUTTON}
</Button>
Just to be complete SignInInput! has the following generated schema
input AuthProviderEmailSignInInput {
email: String!
password: String!
}
input SignUpInput {
email: AuthProviderEmailSignUpInput
}
Actual outcome:
Error occurs. Console error has this:
TypeError: Cannot read property 'data' of undefined at MutationData.onMutationCompleted (react-hooks.cjs.js:654) at react-hooks.cjs.js:579 at tryCallOne (core.js:37) at core.js:123 at JSTimers.js:277 at _callTimer (JSTimers.js:135) at _callImmediatesPass (JSTimers.js:183) at Object.callImmediates (JSTimers.js:446) at MessageQueue.__callImmediates (MessageQueue.js:396) at MessageQueue.js:144
Attaching debugging I tried to follow before the error occurs:
-
first here
-
then here
response is undefined so response.data breaks. Response seems always undefined (both cases of right credentials and wrong ones), and also execution seems always go in the "complete" event function. I was not able to understand the root cause of this.
How to reproduce the issue:
My React Native project has the package.json specied below. Other useful code other than SignIn.tsx is this:
- Return template of my App.tsx
return (
<LocalizationProvider>
<SafeAreaProvider>
<ApolloProvider client={client}>
<AuthContext.Provider value={authContext}>
<NavigationContainer>
{!authState.userToken ? (
<Stack.Navigator>
{authState.isLoading ? (
// We haven't finished checking for the token yet
<Stack.Screen
name="Splash"
component={Splash}
options={{headerShown: false}}
/>
) : (
// No token found, user isn't signed in
<Stack.Screen
name="SignIn"
component={SignInScreen}
options={{
headerTitle: (props) => <LogoTitle {...props} />,
headerStyle: {
height: 100
},
// When logging out, a pop animation feels intuitive
animationTypeForReplace: authState.isSignout
? 'pop'
: 'push'
}}
/>
)}
</Stack.Navigator>
) : (
// User is signed in
<AppNavigator />
)}
</NavigationContainer>
</AuthContext.Provider>
</ApolloProvider>
</SafeAreaProvider>
</LocalizationProvider>
);
client variable is Imported from apollo-client.ts which is this (I followed your Migration guide for Custom configuration):
const errorLink = onError(({graphQLErrors, networkError}) => {
if (graphQLErrors) {
graphQLErrors.map(({message, locations, path}) =>
console.log(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
)
);
}
if (networkError) {
console.log(`[Network error]: ${networkError}`);
}
});
const request = async (operation) => {
//uses async storage to get the saved headers if available
const newHeaders = getHeaders();
operation.setContext({
headers: {
...newHeaders
}
});
};
const requestLink = new ApolloLink(
(operation, forward) =>
new Observable((observer) => {
// @ts-ignore
let handle;
Promise.resolve(operation)
.then((oper) => request(oper))
.then(() => {
handle = forward(operation).subscribe({
next: observer.next.bind(observer),
error: observer.error.bind(observer),
complete: observer.complete.bind(observer)
});
})
.catch(observer.error.bind(observer));
return () => {
// @ts-ignore
if (handle) {
// @ts-ignore
handle.unsubscribe();
}
};
})
);
//this is needed for union types
const fragmentMatcher = new IntrospectionFragmentMatcher({
introspectionQueryResultData: introspectionQueryResultData as any
});
const cache = new InMemoryCache({
addTypename: true,
fragmentMatcher
});
const Client = new ApolloClient({
link: ApolloLink.from([
errorLink,
requestLink,
withClientState({
defaults: {
isConnected: true
},
resolvers: {
Mutation: {
updateNetworkStatus: (_, {isConnected}, {cache}) => {
cache.writeData({data: {isConnected}});
return null;
}
}
},
cache
}),
split(
({query: {definitions}}) =>
definitions.some((node) => {
const {kind, operation} = node as OperationDefinitionNode;
return kind === 'OperationDefinition' && operation === 'subscription';
}),
new HttpLink({
uri: GRAPHQL_ENDPOINT
})
)
]),
cache,
connectToDevTools: true
});
export default Client;
Version
Here's the relevant part of my package.json:
"dependencies": {
"@apollo/react-hooks": "^3.1.4",
"@react-native-community/async-storage": "^1.8.1",
"@react-native-community/masked-view": "^0.1.7",
"@react-navigation/bottom-tabs": "^5.2.6",
"@react-navigation/native": "^5.1.5",
"@react-navigation/stack": "^5.2.10",
"apollo-cache-inmemory": "^1.6.5",
"apollo-client": "^2.6.8",
"apollo-link": "^1.2.13",
"apollo-link-context": "^1.0.19",
"apollo-link-error": "^1.1.12",
"apollo-link-http": "^1.5.16",
"apollo-link-lazy": "^0.0.2",
"apollo-link-state": "^0.4.2",
"apollo-utilities": "^1.3.3",
"babel-plugin-module-resolver": "^4.0.0",
"graphql-tag": "^2.10.3",
"react": "16.11.0",
"react-native": "0.62.2",
"react-native-gesture-handler": "^1.6.1",
"react-native-localization": "^2.1.6",
"react-native-localize": "^1.3.4",
"react-native-paper": "^3.8.0",
"react-native-reanimated": "^1.7.1",
"react-native-safe-area-context": "^0.7.3",
"react-native-screens": "^2.4.0",
"react-native-vector-icons": "^6.6.0"
},
"devDependencies": {
"@babel/core": "^7.6.2",
"@babel/runtime": "^7.6.2",
"@graphql-codegen/cli": "^1.13.1",
"@graphql-codegen/fragment-matcher": "1.13.1",
"@graphql-codegen/introspection": "1.13.1",
"@graphql-codegen/typescript": "1.13.1",
"@graphql-codegen/typescript-operations": "1.13.1",
"@graphql-codegen/typescript-react-apollo": "1.13.1",
"@react-native-community/eslint-config": "^1.0.0",
"@types/graphql": "14.2.3",
"@types/jest": "^24.0.24",
"@types/react": "^16.9.32",
"@types/react-native": "^0.62.0",
"@types/react-native-dotenv": "^0.2.0",
"@types/react-test-renderer": "16.9.2",
"@typescript-eslint/eslint-plugin": "^2.25.0",
"@typescript-eslint/parser": "^2.25.0",
"babel-jest": "^24.9.0",
"eslint": "^6.5.1",
"eslint-import-resolver-babel-module": "^5.1.2",
"eslint-plugin-import": "^2.20.2",
"jest": "^24.9.0",
"metro-react-native-babel-preset": "^0.58.0",
"prettier": "^2.0.2",
"react-devtools": "^4.6.0",
"react-native-dotenv": "^0.2.0",
"react-test-renderer": "16.11.0",
"typescript": "^3.8.3"
},
"resolutions": {
"graphql": "14.5.8"
},
Let me know if more information is needed and I will try to add detail the best that I can. Thank you very much, Andrea
👍 Same error.
Same error.
I gave up stable version. Yesterday I tried 3.0.0-beta.43 with new configuration things and it worked. Anyhow, it would be liked to make v2.x working as well.
For me, I have changed the return value of API, everything is OK now.
Pasting working apollo-client code with apollo 3 Beta. (nothing changed in the other files instead).
import {
ApolloClient,
ApolloLink,
createHttpLink,
InMemoryCache
} from '@apollo/client';
// @ts-ignore
import {GRAPHQL_ENDPOINT} from 'react-native-dotenv';
import {onError} from '@apollo/link-error';
import {getHeaders} from '@utils/authentication';
import {Observable} from '@apollo/client/utilities/observables/Observable';
console.log(GRAPHQL_ENDPOINT);
const httpLink = createHttpLink({
uri: GRAPHQL_ENDPOINT
});
const errorLink = onError(({graphQLErrors, networkError}) => {
if (graphQLErrors) {
graphQLErrors.map(({message, locations, path}) =>
console.log(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
)
);
}
if (networkError) {
console.log(`[Network error]: ${networkError}`);
}
});
const request = async (operation) => {
//uses async storage to get the saved headers if available
const newHeaders = await getHeaders();
operation.setContext({
headers: {
...newHeaders
}
});
};
const requestLink = new ApolloLink(
(operation, forward) =>
new Observable((observer) => {
// @ts-ignore
let handle;
Promise.resolve(operation)
.then((oper) => request(oper))
.then(() => {
handle = forward(operation).subscribe({
next: observer.next.bind(observer),
error: observer.error.bind(observer),
complete: observer.complete.bind(observer)
});
})
.catch(observer.error.bind(observer));
return () => {
// @ts-ignore
if (handle) {
// @ts-ignore
handle.unsubscribe();
}
};
})
);
export default new ApolloClient({
link: ApolloLink.from([errorLink, requestLink, httpLink]),
cache: new InMemoryCache({
addTypename: true
}),
connectToDevTools: true
});
package.json
"dependencies": {
"@apollo/client": "^3.0.0-beta.43",
"@apollo/link-error": "^2.0.0-beta.3",
"@react-native-community/async-storage": "^1.8.1",
"@react-native-community/datetimepicker": "^2.3.2",
"@react-native-community/masked-view": "^0.1.7",
"@react-navigation/bottom-tabs": "^5.2.6",
"@react-navigation/native": "^5.1.5",
"@react-navigation/stack": "^5.2.10",
"babel-plugin-module-resolver": "^4.0.0",
"base-64": "^0.1.0",
"jetifier": "^1.6.5",
"react": "16.11.0",
"react-native": "0.62.2",
"react-native-ble-plx": "^2.0.0",
"react-native-gesture-handler": "^1.6.1",
"react-native-localization": "^2.1.6",
"react-native-localize": "^1.3.4",
"react-native-paper": "^3.8.0",
"react-native-reanimated": "^1.7.1",
"react-native-safe-area-context": "^0.7.3",
"react-native-screens": "^2.4.0",
"react-native-vector-icons": "^6.6.0"
},
"devDependencies": {
"@babel/core": "^7.6.2",
"@babel/runtime": "^7.6.2",
"@graphql-codegen/cli": "^1.13.1",
"@graphql-codegen/fragment-matcher": "1.13.1",
"@graphql-codegen/introspection": "1.13.1",
"@graphql-codegen/typescript": "1.13.1",
"@graphql-codegen/typescript-operations": "1.13.1",
"@graphql-codegen/typescript-react-apollo": "1.13.1",
"@react-native-community/eslint-config": "^1.0.0",
"@types/base-64": "^0.1.3",
"@types/graphql": "14.2.3",
"@types/jest": "^24.0.24",
"@types/react": "^16.9.32",
"@types/react-native": "^0.62.0",
"@types/react-native-dotenv": "^0.2.0",
"@types/react-test-renderer": "16.9.2",
"@typescript-eslint/eslint-plugin": "^2.25.0",
"@typescript-eslint/parser": "^2.25.0",
"babel-jest": "^24.9.0",
"eslint": "^6.5.1",
"eslint-import-resolver-babel-module": "^5.1.2",
"eslint-plugin-import": "^2.20.2",
"graphql-tag": "^2.10.3",
"jest": "^24.9.0",
"metro-react-native-babel-preset": "^0.58.0",
"prettier": "^2.0.2",
"react-devtools": "^4.6.0",
"react-native-dotenv": "^0.2.0",
"react-test-renderer": "16.11.0",
"typescript": "^3.8.3"
},
"resolutions": {
"graphql": "^14.5.8"
},
Hope this would be helpful for others.