React native not connecting to apollo server even use ApolloProvider - react-native

I am having issues with connect react-native project with apollo server.
I followed instruction on Apollo Client https://www.apollographql.com/docs/react/get-started but still having issues get data from apollo server.
Here is my server.js from backend:
const { ApolloServer, gql } = require("apollo-server");
const {
ApolloServerPluginLandingPageLocalDefault,
} = require("apollo-server-core");
const typeDefs = gql`
type Post {
id: Int!
title: String
description: String
author: String
images: String
likes: Int
createdAt: String
}
type Query {
posts: [Post]
}
`;
const posts = [
{
id: 1,
title: "Testing",
description: "post 1",
author: "Nate",
image: "",
likes: 0,
createdAt: "2020-06-01T00:00:00.000Z",
},
{
id: 2,
title: "Post 2",
description: "post 2",
author: "Nathan",
image: "",
likes: 10,
createdAt: "2021-06-01T00:00:00.000Z",
},
];
const resolvers = {
Query: {
posts: () => posts,
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: "bounded",
plugins: [ApolloServerPluginLandingPageLocalDefault({ embed: true })],
});
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
and here is my App.js from react-native project:
import { StyleSheet, Text, View } from "react-native";
import {
ApolloClient,
InMemoryCache,
ApolloProvider,
HttpLink,
from,
gql,
} from "#apollo/client";
import { onError } from "#apollo/client/link/error";
import List from "./components/List";
const errorLink = onError(({ graphqlErrors, networkError }) => {
if (graphqlErrors) {
graphqlErrors.map(({ message, location, path }) => {
console.log(`GraphQL error ${message}`);
});
}
});
const link = from([errorLink, new HttpLink({ uri: "http://localhost:4000/" })]);
const client = new ApolloClient({
uri: "http://localhost:4000/",
cache: new InMemoryCache(),
link: link,
});
const App = () => {
return (
<ApolloProvider client={client}>
<View style={styles.container}>
<List />
</View>
</ApolloProvider>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});
export default App;
List.js:
...
const GET_POSTS = gql`
query GetPosts {
posts {
id
title
description
author
image
likes
createdAt
}
}
`;
const List = () => {
const { loading, error, data } = useQuery(GET_POSTS);
useEffect(() => {
console.log("data: ", data);
}, [data]);
return (
<View>
<Text>Hello world!</Text>
</View>
);
};
export default List;
Can someone tell me where did I do wrong?
Thank you!

Related

Mobile project with expo and hapi.js

Im strugglling with an error that im not capable of get a solution and i dont know if its happening in the front or in the back of the app.
Im trying to follow a tutorial where the guy is setting up an app that records your voice and return it as text from Google API speech to text.
this is the front part, the app is failing in the axios.post, the request is not passing and keeps loading until the error log says it cannot connect to the path.
import React, { Component } from 'react'
import {
StyleSheet, Text, View, TouchableOpacity, ActivityIndicator, Platform,
} from 'react-native'
// import { Audio, Permissions, FileSystem } from 'expo'
import * as Permissions from 'expo-permissions'
import { Audio } from 'expo-av'
import * as FileSystem from 'expo-file-system';
import axios from 'axios'
const styles = StyleSheet.create({
container: {
marginTop: 40,
backgroundColor: '#fff',
alignItems: 'center',
},
button: {
backgroundColor: '#1e88e5',
paddingVertical: 20,
width: '90%',
alignItems: 'center',
borderRadius: 5,
padding: 8,
marginTop: 20,
},
text: {
color: '#fff',
}
})
/*this.recordingSettings = JSON.parse(JSON.stringify(Audio.RECORDING_OPTIONS_PRESET_HIGH_QUALITY = */let recordingOptions = {
android: {
extension: '.m4a',
outputFormat: Audio.RECORDING_OPTION_ANDROID_OUTPUT_FORMAT_MPEG_4,
audioEncoder: Audio.RECORDING_OPTION_ANDROID_AUDIO_ENCODER_AAC,
sampleRate: 44100,
numberOfChannels: 2,
bitRate: 128000,
},
ios: {
extension: '.m4a',
outputFormat: Audio.RECORDING_OPTION_IOS_OUTPUT_FORMAT_MPEG4AAC,
audioQuality: Audio.RECORDING_OPTION_IOS_AUDIO_QUALITY_HIGH,
sampleRate: 44100,
numberOfChannels: 2,
bitRate: 128000,
linearPCMBitDepth: 16,
linearPCMIsBigEndian: false,
linearPCMIsFloat: false,
},
};
export default class SpeechToTextButton extends Component {
constructor(props) {
super(props)
this.recording = null
this.state = {
isRecording: false,
//we would like to know if data fetching is in progress
isFetching: false,
//we will write the transcript result here
transcript: '',
}
}
startRecording = async () => {
// request permissions to record audio
const { status } = await Permissions.askAsync(Permissions.AUDIO_RECORDING)
// if the user doesn't allow us to do so - return as we can't do anything further :(
if (status !== 'granted') return
// when status is granted - setting up our state
this.setState({ isRecording: true })
// basic settings before we start recording,
// you can read more about each of them in expo documentation on Audio
await Audio.setAudioModeAsync({
allowsRecordingIOS: true,
interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,
playsInSilentModeIOS: true,
interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DO_NOT_MIX,
playThroughEarpieceAndroid: true,
})
const recording = new Audio.Recording()
try {
// here we pass our recording options
await recording.prepareToRecordAsync(recordingOptions)
// and finally start the record
await recording.startAsync()
console.log('funcionaaa')
} catch (error) {
console.log(error)
// we will take a closer look at stopRecording function further in this article
this.stopRecording()
console.log('no funca')
}
// if recording was successful we store the result in variable,
// so we can refer to it from other functions of our component
this.recording = recording
}
stopRecording = async () => {
// set our state to false, so the UI knows that we've stopped the recording
this.setState({ isRecording: false })
try {
// stop the recording
await this.recording.stopAndUnloadAsync()
console.log('aca tiene que parar')
} catch (error) {
console.log(error)
}
}
getTranscription = async () => {
// set isFetching to true, so the UI knows about it
this.setState({ isFetching: true })
try {
// take the uri of the recorded audio from the file system
const { uri } = await FileSystem.getInfoAsync(this.recording.getURI())
// now we create formData which will be sent to our backend
const formData = new FormData()
formData.append('file', {
uri,
// as different audio types are used for android and ios - we should handle it
type: Platform.OS === 'ios' ? 'audio/x-wav' : 'audio/m4a',
name: Platform.OS === 'ios' ? `${Date.now()}.wav` : `${Date.now()}.m4a`,
})
// post the formData to our backend
const { data } = await axios.post('http://190.19.68.120/api/speech', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
})
console.log(data)
// set transcript from the data which we received from the api
this.setState({ transcript: data.transcript })
} catch (error) {
console.log('There was an error reading file', error.request)
this.stopRecording()
// we will take a closer look at resetRecording function further down
this.resetRecording()
}
// set isFetching to false so the UI can properly react on that
this.setState({ isFetching: false })
}
deleteRecordingFile = async () => {
// deleting file
try {
const info = await FileSystem.getInfoAsync(this.recording.getURI())
await FileSystem.deleteAsync(info.uri)
} catch (error) {
console.log('There was an error deleting recorded file', error)
}
}
resetRecording = () => {
this.deleteRecordingFile()
this.recording = null
}
handleOnPressOut = () => {
// first we stop the recording
this.stopRecording()
console.log('para en el pressout')
// second we interact with our backend
this.getTranscription()
}
render() {
const {
isRecording, transcript, isFetching,
} = this.state
return (
<View style={styles.container}>
<TouchableOpacity
style={styles.button}
onPressIn={this.startRecording}
onPressOut={this.handleOnPressOut}
>
{isFetching && <ActivityIndicator color="#ffffff" />}
{!isFetching &&
<Text style={styles.text}>
{isRecording ? 'Recording...' : 'Start recording'}
</Text>
}
</TouchableOpacity>
<Text>
{transcript}
</Text>
</View>
)
}
}
Here it is the back part, where i receive the request from the front and send the audio to the google API
'use strict';
const Hapi = require('#hapi/hapi');
const fs = require('fs')
const axios = require('axios')
const speech = require('#google-cloud/speech');
const ffmpeg = require('fluent-ffmpeg');
const client = new speech.SpeechClient();
const init = async () => {
const server = Hapi.server({
port: 3005,
host: 'localhost'
});
server.route({
method: 'POST',
path: '/speech',
config: {
handler: async (request, h) => {
const data = request.payload;
console.log(data)
if (data.file) {
const name = data.file.hapi.filename;
const path = __dirname + "/uploads/" + name;
const encodedPath = __dirname + "/uploads/encoded_" + name;
const file = fs.createWriteStream(path);
file.on('error', (err) => console.error(err));
data.file.pipe(file);
return new Promise(resolve => {
data.file.on('end', async (err) => {
const ret = {
filename: data.name,
headers: data.file.hapi.headers
}
ffmpeg()
.input(path)
.outputOptions([
'-f s16le',
'-acodec pcm_s16le',
'-vn',
'-ac 1',
'-ar 41k',
'-map_metadata -1'
])
.save(encodedPath)
.on('end', async () => {
const savedFile = fs.readFileSync(encodedPath)
const audioBytes = savedFile.toString('base64');
const audio = {
content: audioBytes,
}
const sttConfig = {
enableAutomaticPunctuation: false,
encoding: "LINEAR16",
sampleRateHertz: 41000,
languageCode: "en-US",
model: "default"
}
const request = {
audio: audio,
config: sttConfig,
}
const [response] = await client.recognize(request);
const transcription = response.results
.map(result => result.alternatives[0].transcript)
.join('\n');
fs.unlinkSync(path)
fs.unlinkSync(encodedPath)
resolve(JSON.stringify({ ...ret, transcript: transcription }))
})
})
})
}
},
payload: {
output: 'stream',
parse: true,
}
}
})
await server.start();
console.log('Server running on %s', server.info.uri);
};
process.on('unhandledRejection', (err) => {
console.log(err);
});
init();
i thought i could try migrating the server to express.js but under handler, i got payload key, and i dont know what to do with that in an express server.

Undefined is not a function {near This.state} react Native error

In my react native code I am facing this issue. some time it's work and some time it doesn't.
I am beginner in user of React-redux for state management of component any lead will be appreciated.
import React, { PureComponent } from "react"
import PurchaseInvoiceView from "../Components/Purchaseinvoiceview"
import ReturnInvoiceView from "../Components/Returninvoiceview"
import { connect } from "react-redux"
import { translate } from "../i18n"
import { TabView, SceneMap, TabBar } from "react-native-tab-view"
import styles from "./Styles/InvoiceScreenStyle"
import { Cache } from "react-native-cache"
import AsyncStorage from "#react-native-community/async-storage";
import {
getPurchaseInvoice,
getPurchaseInvoiceFromCache,
getReturnInvoice,
getReturnInvoiceFromCache,
} from "../Redux/Actions/invoiceActions"
class InvoiceScreen extends PureComponent {
state = {
index: 0,
routes: [
{ key: "purchase", title: translate("invoiceScreen.purchase") },
{ key: "return", title: translate("invoiceScreen.return") },
],
token: null,
vansale_id: 0,
user: null,
}
componentDidMount() {
const { dispatch, userData } = this.props
this.setState(
{
token: userData.data.package.token || value.package.token,
vansale_id: userData.data.package.id || value.package.id,
},
() => {
const { token, vansale_id } = this.state
dispatch(getPurchaseInvoice(token, { vansale_id}))
.then(res => {
console.log(res);
if (res.payload.status === true) {
var cache = new Cache({
namespace: "FGMM",
policy: {
maxEntries: 50000,
},
backend: AsyncStorage,
})
cache.setItem("invoiceData", res.payload, function(err) {})
}
})
.catch(err => {
var cache = new Cache({
namespace: "FGMM",
policy: {
maxEntries: 50000,
},
backend: AsyncStorage,
})
cache.getItem("invoiceData", function(err, value) {
if (value) {
if (value.status === true) {
dispatch(getPurchaseInvoiceFromCache(value))
}
}
})
})
dispatch(getReturnInvoice(token, { vansale_id,}))
.then(res => {
console.log(res)
if (res.payload.status === true) {
var cache = new Cache({
namespace: "FGMM",
policy: {
maxEntries: 50000,
},
backend: AsyncStorage,
})
cache.setItem("invoiceReturnData", res.payload, function(err) {})
}
})
.catch(err => {
var cache = new Cache({
namespace: "FGMM",
policy: {
maxEntries: 50000,
},
backend: AsyncStorage,
})
cache.getItem("invoiceReturnData", function(err, value) {
if (value) {
if (value.status === true) {
dispatch(getReturnInvoiceFromCache(value))
}
}
})
})
},
)
var cache = new Cache({
namespace: "FGMM",
policy: {
maxEntries: 50000,
},
backend: AsyncStorage,
})
cache.getItem("userData", function(err, value) {
if (value) {
if (value.status === true) {
}
} else {
this.setState({
token: userData.data.package.token || value.package.token,
vansale_id: userData.data.package.id || value.package.id,
})
}
})
}
render() {
return (
<View style={styles.container}>
<TabView
navigationState={this.state}
activeColor="#777"
inactiveColor="#000"
renderTabBar={props => (
<TabBar
{...props}
indicatorStyle={styles.indicator}
style={styles.tabBar}
labelStyle={styles.labelStyle}
/>
)}
renderScene={SceneMap({
purchase: PurchaseInvoiceView,
return: ReturnInvoiceView,
})}
onIndexChange={index => this.setState({ index })}
initialLayout={{ width: Dimensions.get("window").width }}
/>
</View>
)
}
}
const mapStateToProps = state => {
return {
userData: state.userData,
invoiceData: state.invoiceData,
returnInvoiceData: state.invoiceData.return,
}
}
export default connect(mapStateToProps)(InvoiceScreen)
when I am using this on Android it is working perfectly fine, but for an iOS it's crashing

Cannot read property 'id' of undefined. Variable 'id' has coerced Null value for NonNull type 'ID!'

I am using react native gifted chat and I am trying to figure out how to set _id, text, createdAt, userid, and name to the parameters of my mutation. I have been getting the following errors variable id has coerced null value or cannot read property 'id' is undefined. The main question I have is what to set messageid and messagetext to. I am using react native gifted chat with AWS.
export const createMessage = `mutation createMessage($id: ID! $groupchatid: ID! $message: String! $createdUser: String! $createdTime: String!) {
createMessage(input:{ id:$id groupchatid:$groupchatid, message:$message, createdUser: $createdUser createdTime: $createdTime}) {
id
groupchatid
message
createdUser
createdTime
}
}`;
const user = Auth.currentAuthenticatedUser();
this.setState({ username: user.username});
}
MessagesMutation = async () => {
const AddMessage = { message: this.state.messages, createdUser: this.state.username, groupchatid: this.state.groupchatname };
const newGroupChatMessage = await API.graphql(graphqlOperation(createMessage, AddMessage));
console.log(JSON.stringify(newGroupChatMessage));
};
componentWillMount() {
this.setState({
messages: [
{
_id: id,
text: message,
createdAt: new Date(),
user: {
_id: createdUser,
name: createdUser,
avatar: 'https://placeimg.com/140/140/any',
},
},
],
})
}
componentDidMount() {
const { navigation } = this.props;
const value = navigation.getParam('value')
this.setState({groupchatname: value})
}
onSend(messages = []) {
this.setState(previousState => ({
messages: GiftedChat.append(previousState.messages, messages),
}))
}
render(){
const { groupchatname} = this.state;
return (
<SafeAreaView style={{ flex: 1 }}>
<Header style={styles.headerColor}>
<Text style={styles.text}>{groupchatname}</Text>
</Header>
<GiftedChat
messages={this.state.messages}
renderUsernameOnMessage={true}
onSend={messages => this.onSend(messages), this.MessagesMutation}
user={{
_id: this.user,
name: this.user,
avatar: 'https://placeimg.com/140/140/any'
}}```
You 've defined id as a parameter
createMessage($id: ID! $groupchatid: ID! $message: String! $createdUser: String!
$createdTime: String!)
and have forgotten to pass an argument
const AddMessage = {
id:"valu...." //here
message: this.state.messages,
createdUser: this.state.username,
groupchatid: this.state.groupchatname
};

can't set response from api to messages array of GiftedChat

I am new to react native. I am currently developing a messaging app.
I have used npm-giftedChat for UI & functionalities. The problem is I need to get the response from api & set it to the messages array of giftedchat. I receive data from API and while I set it to messages array it loops over data and renders only the last data in that array.
Any help would be appreciated.I have added my code here
Please find where I am going wrong?
componentWillMount() {
var arrMsg = [];
var data = params.data
for(let i = 0; i < data.Replies.length ; i++){
var obj = {
_id: data.To._id,
text: data.Replies[i].Reply,
createdAt: data.Replies[i].CreatedDate,
user: {
_id: data.From._id,
name: 'React Native',
avatar: data.From.Profile.DisplayPicture
},
image: '',
}
arrMsg.push(obj)
}
this.setState({messages: arrMsg})
}
Sample output
My self also facing same issues..
setting is very important in gifted chat..
so try to use following in ur code,i have edited same like your code.if any queries let me know thanks.
for (let i = 0; i < data.Replies.length; i++) {
console.log(data.Replies[i].CreatedDate);
debugger
var id = data.From._id
if (data.To.id == UserID) {
id = this.state.userID
}
const obj = {
_id: Math.round(Math.random() * 1000000),
text: data.Replies[i].Reply,
createdAt: data.Replies[i].CreatedDate,
user: {
_id: id,
name: 'React Native',
avatar: data.From.Profile.DisplayPicture
},
image: '',
}
arrMsg.push(obj);
};
this.setState((previousState) => {
return {
messages: GiftedChat.append(previousState.messages, arrMsg)
};
});
I wrote a gist here on how to add a web socket listening to a rails channel to a react native chat screen + Gifted Chat
// chat.js
import React, { Component } from 'react';
import {
Text,
View,
StyleSheet,
TouchableHighlight,
Dimensions,
AppState,
AsyncStorage,
Alert
} from 'react-native';
import {
GiftedChat,
Actions,
Bubble,
SystemMessage
} from 'react-native-gifted-chat';
import axios from 'axios';
import ActionCable from 'react-native-actioncable';
import { yourRootUrl, websocketUrl } from '../config/constants';
class Chat extends Component {
state = {
messages: [],
client: '',
accessToken: '',
expiry: '',
uid: '',
userId: ''
}
componentDidMount() {
AsyncStorage.multiGet(
['client', 'expiry',
'access_token', 'uid',
'account_balance', 'userId'
]
)
.then((result) => {
this.setState({
client: result[0][1],
expiry: result[1][1],
accessToken: result[2][1],
uid: result[3][1],
userId: result[5][1]
});
})
.then(() => {
this.getPreviousMessages();
})
.then(() => {
this.createSocket();
})
.catch(() => {
//error logic
});
}
getPreviousMessages() {
//when we open the chat page we should load previous messages
const { chatId } = this.props.navigation.state.params;
const { client, accessToken, uid, userId } = this.state;
const url = yourRootUrl + '/chats/' + chatId;
const headers = {
'access-token': accessToken,
client,
expiry,
uid
};
axios.get(url, { headers })
.then((response) => {
/*
lets construct our messages to be in
same format as expected by GiftedChat
*/
const allMessages = [];
response.data.included.forEach((x) => {
if (x.attributes.system) {
const sysMessage = {
_id: x.id,
text: x.attributes['message-text'],
createdAt: new Date(x.attributes['created-at']),
system: true
};
allMessages.push(sysMessage);
} else {
const userMessage = {
_id: x.id,
text: x.attributes['message-text'],
createdAt: new Date(x.attributes['created-at']),
user: {
_id: x.attributes['sender-id'],
avatar: x.attributes['sender-avatar'],
},
image: x.attributes.image,
};
allMessages.push(userMessage);
}
});
if (allMessages.length === response.data.included.length) {
//lets sort messages according to date created
const sortAllMessages = allMessages.sort((a, b) =>
b.createdAt - a.createdAt
);
this.setState((previousState) => {
return {
messages: GiftedChat.append(previousState.messages, sortAllMessages)
};
});
}
})
}
createSocket() {
//assuming you have set up your chatchannel in your rails backend
const { client, accessToken, uid, userId } = this.state;
const { chatId } = this.props.navigation.state.params; //using react-navigation
const WEBSOCKET_HOST = websocketUrl +
'access-token=' + accessToken + '&client=' +
client + '&uid=' + uid;
const cable = ActionCable.createConsumer(WEBSOCKET_HOST);
this.channel = cable.subscriptions.create(
{
channel: 'ChatChannel',
id: chatId
}, {
received: (data) => {
console.log('Received Data:', data);
if ((data.message.sender_id !== parseInt(userId))
|| (data.message.image !== null)) {
//ensuring you do not pick up your own messages
if (data.message.system === true) {
const sysMessage = {
_id: data.message.id,
text: data.message.message_text,
createdAt: new Date(data.message.created_at),
system: true
};
this.setState((previousState) => {
return {
messages: GiftedChat.append(previousState.messages, sysMessage)
};
});
} else {
const userMessage = {
_id: data.message.id,
text: data.message.message_text,
createdAt: new Date(data.message.created_at),
user: {
_id: data.message.sender_id,
avatar: data.message.sender_avatar,
},
image: data.message.image,
};
this.setState((previousState) => {
return {
messages: GiftedChat.append(previousState.messages, userMessage)
};
});
}
}
},
connected: () => {
console.log(`Connected ${chatId}`);
},
disconnected: () => {
console.warn(`${chatId} was disconnected.`);
},
rejected: () => {
console.warn('connection rejected');
},
});
}
onSend(messages = []) {
const { chatId } = this.props.navigation.state.params;
const { client, accessToken, uid, userId } = this.state;
this.setState((previousState) => {
return {
messages: GiftedChat.append(previousState.messages, messages)
};
});
messages.forEach((x) => {
const url = yourRootUrl + '/messages';
const headers = {
'access-token': accessToken,
client,
expiry,
uid
};
const data = {
chat_id: chatId,
sender_id: userId,
sender_name: name,
message_text: x.text,
image: x.image
};
/*
send the message to your rails app backend
hopefully you have a callback in your model like
after_create :broadcast_message
then broadcast to the chat channel from your rails backend
*/
axios.post(url, data, { headers })
.then(response => console.log(response));
});
}
renderBubble(props) {
return (
<Bubble
{...props}
wrapperStyle={{
left: {
backgroundColor: '#f9f9f9',
}
}}
/>
);
}
renderSystemMessage(props) {
return (
<SystemMessage
{...props}
containerStyle={{
marginBottom: 15,
}}
textStyle={{
fontSize: 14,
textAlign: 'center'
}}
/>
);
}
render() {
return (
<GiftedChat
messages={this.state.messages}
onSend={message => this.onSend(message)}
user={{
_id: parseInt(userId)
}}
renderBubble={this.renderBubble}
renderSystemMessage={this.renderSystemMessage}
/>
);
}
}

React Native + Redux component renders before store action's complete

I have react native application with redux, where user get nevigated to home component after successful login. But home component get rendered before it receive user profile through store. If I use 'Home' component as connected component then on re-render it receives profile.
It is a correct flow or do I able to delay rendering of 'Home' till store is populated with new data.
Here is code
Types
export const FETCH_PROFILE = 'FETCH_PROFILE';
export const UPDATE_PROFILE = 'UPDATE_PROFILE';
export const DELETE_PROFILE = 'DELETE_PROFILE';
export const FETCH_STREAMS = 'FETCH_STREAMS';
Reducer
export default function profile(state = {}, action) {
switch (action.type) {
case types.FETCH_PROFILE:
return {
...state,
profile: action.profile
}
case types.UPDATE_PROFILE:
return {
...state,
profile: action.profile
}
case types.DELETE_PROFILE:
return {
...state,
profile: null
};
default:
return state;
}
}
Actions
var PROFILE_KEY = "#myApp:profile";
export function fetchProfile() {
return dispatch => {
AsyncStorage.getItem(PROFILE_KEY)
.then((profileString) => {
dispatch({
type: types.FETCH_PROFILE,
profile: profileString ? JSON.parse(profileString) : {}
})
})
}
}
export function updateProfile(data) {
return dispatch => {
AsyncStorage.setItem(PROFILE_KEY, JSON.stringify(data))
.then(() => {
dispatch({
type: types.UPDATE_PROFILE,
profile: data
})
})
}
}
export function deleteProfile() {
return dispatch => {
AsyncStorage.removeItem(PROFILE_KEY)
.then(() => {
dispatch({
type: types.DELETE_PROFILE
})
})
}
}
Login Component
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
username: "",
password: "",
error: "",
showProgress: false,
};
}
_focusNextField(nextField) {
this.refs[nextField].focus();
}
_onLoginPressed() {
this.setState({showProgress: true});
this._login();
}
async _login() {
try {
let response = await fetch( BASE_URL + url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
user: {
email: this.state.username,
password: this.state.password,
}
})
});
let res = await response.text();
if (response.status >= 200 && response.status < 300) {
let user = JSON.parse(res);
this.props.updateProfile(user.user);
this.setState({showProgress: false});
this.props.navigator.replace({name: 'Home'});
}
else {
let error = JSON.parse(res);
throw error.errors;
}
} catch(error) {
this.setState({error: error});
this.setState({showProgress: false});
console.log("error " + error);
}
}
render() {
return (
<View style={styles.loginBox}>
<TextInput
ref="username"
value={this.state.username}
placeholder="Username"
keyboardType="email-address"
onChangeText={(username) => this.setState({username}) }
onSubmitEditing={() => this._focusNextField('password')}/>
<TextInput
ref="password"
placeholder="Password"
value={this.state.password}
secureTextEntry={true}
onChangeText={(password) => this.setState({password}) }
returnKeyType="go"/>
<Button textStyle={{fontSize: 14}} onPress={this._onLoginPressed.bind(this)} style={{marginTop: 30}}>
Sign In
</Button>
</View>
);
}
}
const styles = StyleSheet.create({
loginBox: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
alignItems: 'stretch',
margin: 10,
}
});
var {updateProfile} = require('../Actions');
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
module.exports = connect(
null,
(dispatch) => {
return bindActionCreators({updateProfile}, dispatch)
}
)(Login)
Home
class Home extends React.Component {
render() {
return (
<View style={{flex: 1, backgroundColor: '#fff'}}>
<Text style={{margin: 10, fontSize: 15, textAlign: 'left'}}>I'm in the Drawer!</Text>
<Text>Auth key : {this.props.profile ? this.props.profile.authentication_token : 'authentication_token'}</Text>
</View>
);
}
}
//module.exports = Home;
import { connect } from 'react-redux';
module.exports = connect(
(state) => {
return {
profile: state.profile
}
},
null
)(Home)
If you're using redux-thunk, you can delay the transition until data is loaded. You need to change some small things.
Add return to action creator.
export function updateProfile(data) {
return dispatch => {
return AsyncStorage.setItem(PROFILE_KEY, JSON.stringify(data))
.then(() => {
dispatch({
type: types.UPDATE_PROFILE,
profile: data
})
})
}
}
add await
if (response.status >= 200 && response.status < 300) {
let user = JSON.parse(res);
await this.props.updateProfile(user.user);
this.setState({showProgress: false});
this.props.navigator.replace({name: 'Home'});
}