I'm pretty new to graphql and react native. I'm working on a project where I am trying to create a sign-up screen I'm currently getting a 400 error stating: Possible Unhandled Promise Rejection. I was able to get this screen to work earlier, but I'm trying to use graphql input in my mutation. Currently I have:
import React, { useState } from 'react';
import {
View,
Text,
TextInput,
Pressable,
ActivityIndicator,
Alert,
} from 'react-native';
import AsyncStorage from '#react-native-async-storage/async-storage';
import { useNavigation } from '#react-navigation/native';
import { RootStackParamList, MessageNavProps } from '../navigation/types';
import { StackNavigationProp } from '#react-navigation/stack';
import Checkbox from 'expo-checkbox';
import { useMutation, gql } from '#apollo/client';
const SIGN_UP_MUTATION = gql`
mutation signup($input: UserInput!}) {
signup(input: $input){
token
}
}
`;
const SignupScreen = () => {
const [email, setEmail] = useState('');
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [birth_date, setBirth_date] = useState('');
const [genderF, setGenderF] = useState(false);
const [genderM, setGenderM] = useState(false);
const [genderNB, setGenderNB] = useState(false);
const { navigate } = useNavigation<StackNavigationProp<RootStackParamList>>()
AsyncStorage.getItem('token').then((res) => console.log(res))
const [signup, { data, error, loading }] = useMutation(SIGN_UP_MUTATION);
if (error) {
Alert.alert('Error signing up. Try again' + error.message)
}
if (data) {
AsyncStorage
.setItem('token', data.signup.token)
.then(() => {
console.log(data.signup.token)
navigate('Home')
}).catch(function(error){
console.log('saving erro ' + error.message);
})
}
const onSubmit = () => {
signup({variables: /*{input:*/{firstName, lastName, username, email, password, basicInfo: { birth_date, gender_identity: {female: genderF, male: genderM, nonbinary: genderNB}, }}})
}
return (
<View style={{ padding: 20 }}>
<TextInput
placeholder="firstName"
value={firstName}
onChangeText={setFirstName}
style={{
fontSize: 18,
width: '100%',
marginVertical: 25,
}}
/>
...
<Pressable
onPress={onSubmit}
style={{
backgroundColor: '#e33062',
height: 50,
borderRadius: 5,
alignItems: 'center',
flexDirection: 'row',
justifyContent: 'center',
marginTop: 30,
}}
>
{loading && <ActivityIndicator />}
<Text
style={{
color: 'white',
fontSize: 18,
fontWeight: 'bold'
}}>
Sign up
</Text>
</Pressable>
</View>
)
}
export default SignupScreen;
In my backend:
input UserInput {
username: String
email: String!
firstName: String
lastName: String
password: String
basicInfo: BasicInfoInput!
}
input BasicInfoInput {
birth_date: String!
gender_identity: GenderIndentityInput!
}
input GenderIndentityInput {
female: Boolean
male: Boolean
non_binary: Boolean
}
type Mutation {
signup(input: UserInput! ): Auth
}
In apollo graphql studio,
mutation{
signup(
$input:
{email:"", firstName:"", lastName:"", username:"", password:"",
basicInfo: { birth_date: "", gender_identity: { male: "", female: "", nonbinary: ""}}
}
)
{
token,
}
}
worked.
I tried changing my SIGN_UP_MUTATION to:
const SIGN_UP_MUTATION = gql`
mutation signup($input: {$email: String!, $firstName: String!, $lastName: String!, $password: String!, $username: String!, $basicInfo: { $birth_date: String!, $gender_identity: { $female: Boolean!, $male: Boolean!, $nonbinary: Boolean!}} }) {
signup(input: $input){
token
}
}
`;
but this didn't work either. I would really appreciate any help or advice on what I'm doing wrong. Thank you!
Also, before, I had:
const SIGN_UP_MUTATION = gql`
mutation signup($email: String!, $firstName: String!, $lastName: String!, $password: String!, $username: String!, $avatar: String) {
signup(email: $email, firstName: $firstName, lastName: $lastName, password: $password, username: $username, avatar: $avatar){
token
}
}
`;
with
const onSubmit = () => {
signup({variables: {firstName, lastName, username, email, password }})
}
which worked
Related
I'm trying to use React-slick with gatsby-plugin images and I have the page setup like this.
import React from "react";
import { graphql } from "gatsby"
import Slider from "react-slick";
import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css";
import { GatsbyImage } from "gatsby-plugin-image"
const settings = {
autoPlay: true,
arrows: false,
dots: true,
infinite: true,
speed: 500,
slidesToShow: 1,
slidesToScroll: 1,
};
const ImgSlide = ({ data }) => {
return (
<div>
<Slider {...settings}>
<div>
<GatsbyImage fluid={data.image1.childImageSharp.fluid} />
</div>
<div>
<GatsbyImage fluid={data.image2.childImageSharp.fluid} />
</div>
</Slider>
</div>
);
};
export const pageQuery = graphql`
query {
image1: file(relativePath: { eq: "images/icon.png" }) {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
image2: file(relativePath: { eq: "images/icon.png" }) {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
}
`
export default ImgSlide;
When i run Gatsby develop I get an error saying image1 is not defined. I really don't know what I'm missing here. I think it has something to do with how I'm trying to define image1 but I'm pretty sure I've used relativePath properly unless I'm not specifying the location properly.
I do have the same image specified twice that is just because I have not imported the photos in just yet I'm just testing to make it work.
gatsby-config setup is
module.exports = {
siteMetadata: {
title: "Inkd Era",
description: "Clothing and brand built for tattoo and tattoed culture",
},
plugins: [
"gatsby-plugin-sass",
"gatsby-plugin-image",
"gatsby-plugin-react-helmet",
"gatsby-plugin-sitemap",
{
resolve: "gatsby-plugin-manifest",
options: {
icon: "src/images/icon.png",
},
},
"gatsby-transformer-remark",
"gatsby-plugin-sharp",
"gatsby-transformer-sharp",
{
resolve: "gatsby-transformer-remark",
options: {
plugins: [
{
resolve: "gatsby-remark-images",
options: {
maxWidth: 650,
},
},
],
},
},
{
resolve: "gatsby-source-filesystem",
options: {
name: "images",
path: `${__dirname}/src/images/`,
},
__key: "images",
},
{
resolve: "gatsby-source-filesystem",
options: {
name: "pages",
path: `${__dirname}/src/pages/`,
},
__key: "pages",
},
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `Inkd Era`,
short_name: `Inkd era`,
start_url: `/`,
background_color: `#000`,
theme_color: `#fafafa`,
display: `standalone`,
icon: `content/assets/gatsby-icon.png`,
},
},
],
};
The structure for the new <GatsbyImage> component when passing the image itself is using the image prop, not fluid. In addition, the query needs to fetch gatsbyImageData, not fluid as you can see in the docs:
import { graphql } from "gatsby"
import { GatsbyImage, getImage } from "gatsby-plugin-image"
function BlogPost({ data }) {
const image = getImage(data.blogPost.avatar)
return (
<section>
<h2>{data.blogPost.title}</h2>
<GatsbyImage image={image} alt={data.blogPost.author} />
<p>{data.blogPost.body}</p>
</section>
)
}
export const pageQuery = graphql`
query {
blogPost(id: { eq: $Id }) {
title
body
author
avatar {
childImageSharp {
gatsbyImageData(
width: 200
placeholder: BLURRED
formats: [AUTO, WEBP, AVIF]
)
}
}
}
}
`
In your scenario, you are mixing the gatsby-image approach, from Gatsby v2 with the new gatsby-plugin-image, which stills in beta, but it's from the v3.
If you want to use the <GatsbyImage>, adapt the query and the component to the needs, otherwise, use the gatsby-image properly like:
import Img from `gatsby-image`
<Img fluid={data.image1.childImageSharp.fluid} />
I am having trouble deleting a MongoDB document using Apollo Client. I don't think my query syntax is the cause because I tested the query in Graphiql and it works fine. This is the error I am getting:
Unhandled Runtime Error
Error: Response not successful: Received status code 500
Call Stack
new ApolloError
node_modules/#apollo/client/errors/index.js (26:0)
Object.error
node_modules/#apollo/client/core/QueryManager.js (127:0)
notifySubscription
node_modules/zen-observable/lib/Observable.js (140:0)
onNotify
node_modules/zen-observable/lib/Observable.js (179:0)
SubscriptionObserver.error
node_modules/zen-observable/lib/Observable.js (240:0)
eval
node_modules/#apollo/client/utilities/observables/iteration.js (4:48)
Array.forEach
<anonymous>
iterateObserversSafely
node_modules/#apollo/client/utilities/observables/iteration.js (4:0)
Object.error
node_modules/#apollo/client/utilities/observables/Concast.js (35:42)
notifySubscription
node_modules/zen-observable/lib/Observable.js (140:0)
onNotify
node_modules/zen-observable/lib/Observable.js (179:0)
SubscriptionObserver.error
node_modules/zen-observable/lib/Observable.js (240:0)
eval
node_modules/#apollo/client/link/http/createHttpLink.js (110:0)
This is my code for the back end:
const CompanyType = new GraphQLObjectType({
name: 'Company',
fields: () => ({
_id: { type: GraphQLString },
name: { type: GraphQLString },
description: { type: GraphQLString },
users: {
type: new GraphQLList(UserType),
resolve(parentValue, args) {
return User.findUsers(parentValue._id);
},
},
}),
});
const mutation = new GraphQLObjectType({
name: 'Mutation',
fields: {
deleteCompany: {
type: CompanyType,
args: { _id: { type: new GraphQLNonNull(GraphQLString) } },
resolve(parentValue, { _id }) {
return Company.remove({ _id }).catch((err) => console.log(err));
},
},
},
});
This is my code for my React frontend
import React from 'react';
import { gql, useMutation } from '#apollo/client';
const DELETE_COMPANY = gql`
mutation DeleteCompany($id: String!) {
deleteCompany(_id: $id) {
_id
}
}
`;
const CompanyList = () => {
const { loading: loadingList, error: errorList, data: dataList } = useQuery(
COMPANY_LIST
);
const [
deleteCompany,
{ loading: loadingDelete, error: errorDelete, data: dataDelete },
] = useMutation(DELETE_COMPANY);
const renderCompanies = () =>
dataList.companies.map((company) => (
<li key={company._id}>
{company.name}
<button
onClick={() => {
deleteCompany({ variables: { _id: company._id } });
}}
>
delete
</button>
</li>
));
return (
<div>
{loadingList || loadingDelete ? <h1>Loading...</h1> : renderCompanies()}
</div>
);
};
The component for route 'FilmDetail' must be a React Component
I'm trying to use react-navigation but I can't get it to work. I've tried removing brackets while importing and can still reproduce the error:
Navigaton.js
import React from 'react'
import { StyleSheet, Image } from 'react-native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs'
import { createStackNavigator } from 'react-navigation-stack'
import { createAppContainer } from 'react-navigation'
import Search from '../Components/Search'
import FilmDetail from '../Components/FilmDetail'
import Favorites from '../Components/Favorites'
const SearchStackNavigator = createStackNavigator({
Search: {
screen: Search,
navigationOptions: {
title: 'Rechercher'
}
},
FilmDetail: {
screen: FilmDetail
}
})
const MoviesTabNavigator = createBottomTabNavigator(
{
Search: {
screen: SearchStackNavigator,
navigationOptions: {
tabBarIcon: () => {
return <Image
source={require('../Images/ic_search.png')}
style={styles.icon}/>
}
}
},
Favorites: {
screen: Favorites,
navigationOptions: {
tabBarIcon: () => {
return <Image
source={require('../Images/ic_favorite.png')}
style={styles.icon}/>
}
}
}
},
{
tabBarOptions: {
activeBackgroundColor: '#DDDDDD',
inactiveBackgroundColor: '#FFFFFF',
showLabel: false,
showIcon: true
}
}
)
const styles = StyleSheet.create({
icon: {
width: 30,
height: 30
}
})
export default createAppContainer(MoviesTabNavigator)
App.js
import React from 'react'
import Navigation from './Navigation/Navigation'
import { Provider } from 'react-redux'
import Store from './Store/configureStore'
export default class App extends React.Component {
render() {
return (
<Provider store={Store}>
<Navigation/>
</Provider>
)
}
}
FilmDetail.js
import React from 'react'
import { StyleSheet, View, Text, ActivityIndicator, ScrollView, Image, Button ,TouchableOpacity} from 'react-native'
import {getImageFromApi} from '../API/TMDBApi'
import getFilmDetailFromApi from '../API/TMDBApi'
import moment from 'moment'
import numeral from 'numeral'
import { connect } from 'react-redux'
class FilmDetail extends React.Component {
constructor(props) {
super(props)
this.state = {
film: undefined,
isLoading: true
}
}
componentDidMount() {
getFilmDetailFromApi(this.props.navigation.state.params.idFilm).then(data => {
this.setState({
film: data,
isLoading: false
})
})
}
componentDidUpdate() {
console.log("componentDidUpdate : ")
console.log(this.props.favoritesFilm)
}
_displayLoading() {
if (this.state.isLoading) {
return (
<View style={styles.loading_container}>
<ActivityIndicator size='large' />
</View>
)
}
}
_toggleFavorite() {
const action = { type: "TOGGLE_FAVORITE", value: this.state.film }
this.props.dispatch(action)
}
_displayFavoriteImage() {
var sourceImage = require('../Images/ic_favorite_border.png')
if (this.props.favoritesFilm.findIndex(item => item.id === this.state.film.id) !== -1) {
// Film dans nos favoris
sourceImage = require('../Images/ic_favorite.png')
}
return (
<Image
style={styles.favorite_image}
source={sourceImage}
/>
)
}
_displayFilm() {
const { film } = this.state
if (film != undefined) {
return (
<ScrollView style={styles.scrollview_container}>
<Image
style={styles.image}
source={{uri: getImageFromApi(film.backdrop_path)}}
/>
<Text style={styles.title_text}>{film.title}</Text>
<TouchableOpacity style={styles.favorite_container} onPress={() => this._toggleFavorite()}>{this._displayFavoriteImage()}</TouchableOpacity>
<Text style={styles.description_text}>{film.overview}</Text>
<Text style={styles.default_text}>Sorti le {moment(new Date(film.release_date)).format('DD/MM/YYYY')}</Text>
<Text style={styles.default_text}>Note : {film.vote_average} / 10</Text>
<Text style={styles.default_text}>Nombre de votes : {film.vote_count}</Text>
<Text style={styles.default_text}>Budget : {numeral(film.budget).format('0,0[.]00 $')}</Text>
<Text style={styles.default_text}>Genre(s) : {film.genres.map(function(genre){
return genre.name;
}).join(" / ")}
</Text>
<Text style={styles.default_text}>Companie(s) : {film.production_companies.map(function(company){
return company.name;
}).join(" / ")}
</Text>
</ScrollView>
)
}
}
render() {
return (
<View style={styles.main_container}>
{this._displayLoading()}
{this._displayFilm()}
</View>
)
}
}
const styles = StyleSheet.create({
main_container: {
flex: 1
},
loading_container: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
alignItems: 'center',
justifyContent: 'center'
},
scrollview_container: {
flex: 1
},
image: {
height: 169,
margin: 5
},
title_text: {
fontWeight: 'bold',
fontSize: 35,
flex: 1,
flexWrap: 'wrap',
marginLeft: 5,
marginRight: 5,
marginTop: 10,
marginBottom: 10,
color: '#000000',
textAlign: 'center'
},
description_text: {
fontStyle: 'italic',
color: '#666666',
margin: 5,
marginBottom: 15
},
default_text: {
marginLeft: 5,
marginRight: 5,
marginTop: 5,
},favorite_container: {
alignItems: 'center'
},favorite_image: {
width: 40,
height: 40
}
})
const mapStateToProps = (state) => {
return {
favoritesFilm: state.favoritesFilm
}
}
export default connect(mapStateToProps)(FilmDetail)
Your displayLoading and displayFilm functions need to return null. Currently they only return if the happy path is followed, but that can lead to weird stuff happening if they don't return null for the other paths where they shouldn't display themselves.
I'm not sure if that will fix your error or not, I am not seeing anything else sticking out to me, but I would implement that and see if your issue goes away.
If that doesn't work, try not using React-Navigation for a second and just import/render the FilmDetail component by itself to see if a different error comes up that may be the underlying issue.
If not let me know and I'll look again.
I fix it by changing my "react-navigation": "^1.6.1" to "react-navigation": "^4.3.9" and instead of using #react-navigation/bottom-tabs i tried using react-navigation-tabs
I was trying to update the user profile but the profile picture only changes ones.To change it each time i had to change the image name each time how to solve it.I have tried to send the request in post method but my api does not support post.I will post my code below.Could some one help me and Thanks in advance.
class ProfileEdit extends Component {
state = {
username: '',
email: '',
about: '',
userInfo: '',
avatarSource: null,
showAlert: false,
showCancelButton: false,
showConfirmButton: false,
};
constructor(props) {
super(props);
this.selectPhotoTapped = this.selectPhotoTapped.bind(this);
}
hideAlert = () => {
this.setState({
showAlert: false
});
};
selectPhotoTapped() {
const options = {
quality: 1.0,
maxWidth: 500,
maxHeight: 500,
storageOptions: {
skipBackup: true,
},
};
ImagePicker.showImagePicker(options, response => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled photo picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
} else {
const source = { uri: response.uri }
this.setState({
avatarSource: source,
});
this.upLoadImage(response.uri);
}
});
}
upLoadImage = async (image_uri) => {
const value = await AsyncStorage.getItem('userToken');
//alert(value)
var url = 'http://www.dev.beta.duklr.com:8000/api/v2/profile/';
var b_url = url + value + '/';
let data = new FormData();
data.append('photo', { type: 'image/jpg', uri: image_uri, name: 'profile_image1.jpg' });
data.append('Content-Type', 'image/jpg');
fetch(b_url, {
method: 'PUT',
body: data
}).then((res) => res.json())
.then((res) => {
// alert("response" + JSON.stringify(res));
})
.catch((e) => this.setState({
showAlert: true,
message: e,
showCancelButton: true,
cancelText: 'close',
}))
.done()
}
componentDidMount = async () => {
const value = await AsyncStorage.getItem('userToken');
//alert(value)
var url = 'http://www.dev.beta.duklr.com:8000/api/v2/profile/';
var b_url = url + value + '/';
//alert(value);
return fetch(b_url)
.then(res => res.json())
.then(res => {
this.setState(
{
isLoading: false,
refreshing: false,
userInfo: res,
},
function () { }
);
})
.catch(error => {
this.setState({
showAlert: true,
message: error,
showCancelButton: true,
cancelText: 'close',
})
});
}
onUpdate = async () => {
const value = await AsyncStorage.getItem('userToken');
var url = 'my_api';
var b_url = url + value + '/';
//alert(b_url);
const { email, about, avatarSource } = this.state;
//alert(`${email},${about}`);
fetch(b_url, {
method: 'PUT',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: email,
about_us: about,
}),
})
.then((response) => response.json())
.then((responseJson) => {
this.setState({
showAlert: true,
message: "Saved successfully",
showCancelButton: true,
cancelText: 'close',
})
// this.setState({
// dataSource: responseJson.promptmsg,
// })
})
.catch((error) => {
this.setState({
showAlert: true,
message: error,
showCancelButton: true,
cancelText: 'close',
})
});
}
catch(errors) {
this.setState({
showAlert: true,
message: errors,
showCancelButton: true,
cancelText: 'close',
});
}
render() {
const value_email = this.state.userInfo.email;
const value_about = this.state.userInfo.about_us;
return (
<View style={styles.continer}>
<ScrollView>
<View style={{ alignItems: 'center', padding: 20 }}>
<Avatar
source={this.state.avatarSource}
size="xlarge"
// showEditButton
onPress={this.selectPhotoTapped.bind(this)}
/>
</View>
<View style={styles.textContiner}>
{/* <TextField
label='User Name'
title={this.state.userInfo.name}
value={this.state.username}
onChangeText={(username) => this.setState({ username })}
/> */}
<TextField
label='Email Id'
placeholder={value_email}
//value={value_email}
onChangeText={(email) => this.setState({ email })}
/>
<TextField
label='About'
//value={value_about}
placeholder={value_about}
onChangeText={(about) => this.setState({ about })}
/>
<View style={{ marginTop: 20 }}>
<Button
title="Save"
onPress={this.onUpdate.bind(this)}>
</Button>
</View>
</View>
</ScrollView>
<AwesomeAlert
show={this.state.showAlert}
showProgress={false}
title="Hello There"
message={this.state.message}
closeOnTouchOutside={true}
closeOnHardwareBackPress={true}
showCancelButton={this.state.showCancelButton}
showConfirmButton={this.state.showConfirmButton}
cancelText={this.state.cancelText}
confirmText={this.state.confirmText}
confirmButtonColor="#DD6B55"
onCancelPressed={() => {
this.hideAlert();
}}
onConfirmPressed={() => {
this.hideAlert();
}}
/>
</View>
);
}
}
export default ProfileEdit;
Is Avatar based on React Native's Image? To my experience, the Image component shipped with React Native is very buggy. Indeed, reloading issue is one of them. I often use FastImage as replacement for Image.
I've implemented https://reactnavigation.org/docs/en/auth-flow.html as described with a SwitchNavigator. However, my AuthScreen is never unmounted when I navigate to App.
I'm, using a SwitchNavigator, with in it a screen and a DrawerNavigator, as well as some StackNavigators. I've tried changing the structure of my navigators, but that doesn't seem to have any effect.
const AppStack = createDrawerNavigator(
{
StackA: {
name: 'someStackNavigator',
screen: someStackNavigator
},
},
{
...
});
const AppNavigator = createSwitchNavigator(
{
App: AppStack,
Auth: {
screen: AuthScreen
}
},
{
initialRouteName: 'App'
});
const AppContainer = createAppContainer(AppNavigator);
export default AppContainer;
How do I force the Auth screen in the SwitchNavigator to be unmounted if you navigate to a screen in the other stacks/drawers?
Like this?
import React, { Component } from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import {
createSwitchNavigator,
createStackNavigator,
createAppContainer,
createDrawerNavigator,
} from 'react-navigation';
class Screen extends Component {
render() {
return (
<View style={styles.container}>
<Text>Screen</Text>
</View>
);
}
}
class AuthScreen extends Component {
componentDidMount() {
console.log('componentDidMount');
}
componentWillUnmount() {
console.log('componentWillUnmount');
}
render() {
return (
<View style={styles.container}>
<Text>Auth Screen</Text>
<TouchableOpacity onPress={() => this.props.navigation.navigate('App')}>
<Text>Login</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
marginTop: 40,
justifyContent: 'center',
alignItems: 'center',
},
});
const SomeStackNavigator = createStackNavigator({
ScreenA: Screen,
ScreenB: Screen,
});
const AppStack = createDrawerNavigator({
StackA: {
name: 'StackA',
screen: SomeStackNavigator,
},
StackB: {
name: 'StackB',
screen: SomeStackNavigator,
},
});
const AppNavigator = createSwitchNavigator(
{
App: AppStack,
Auth: {
screen: AuthScreen,
},
},
{
initialRouteName: 'Auth',
},
);
const AppContainer = createAppContainer(AppNavigator);
export default AppContainer;
You can try it here. You can see in the console that AuthScreen is unmounted when the login button is clicked.