I have an application created with Expo and the wing which has a contact form from which to send inquiries.
I have started with the application already built, I am just setting my data.
The problem is that the sent queries do not reach the mail that I have established in the configuration, in a file (config.php) so that the messages must arrive in smtp mode
This is my server configuration:
$emailConfig = array(
'address' => 'xxxxxxx',
'password' => 'xxxx',
'name' => 'jose',
'smtp_host' => 'smtp.xxxx.es',
'smtp_port' => '587',
'smtp_encrypt' => 'tls'
);
The application, the debugging console shows me the following when I click SEND:
Toast is not defined
* application/components/PlaceFav.js:82:10 in render
- node_modules/react-native/node_modules/promise/setimmediate/core.js:37:11 in tryCallOne
- node_modules/react-native/node_modules/promise/setimmediate/core.js:123:14 in setImmediate$argument_0
- ... 8 more stack frames from framework internals
The file referenced by the console output is as follows, the line :
renderItem={({item, index}) =>
import React, {Component} from 'react';
import * as firebase from 'firebase';
import { NavigationActions, StackNavigator, withNavigation} from 'react-navigation';
import{AsyncStorage, TouchableOpacity, Dimensions, View, Image, ScrollView, FlatList} from 'react-native';
import Icon from 'react-native-vector-icons/SimpleLineIcons';
import { Container, Body, Thumbnail, Text, List, Right, ListItem} from 'native-base';
import ConfigApp from '../utils/ConfigApp';
import FavListEmpty from './FavListEmpty';
import Strings from '../utils/Strings';
var styles = require('../../assets/files/Styles');
var {height, width} = Dimensions.get('window');
class PlaceFav extends React.Component {
constructor(props) {
super(props);
this.state = {
places: []
}
}
componentDidMount () {
this.fetchPlaces();
}
PlaceDetails (item) {
const navigateAction = NavigationActions.navigate({
routeName: 'PlaceDetailsScreen',
params: {item}
});
this.props.navigation.dispatch(navigateAction);
}
renderFooterPlaces = () => {
const places = this.state.places
if (places.length != 0) return null;
return (
<FavListEmpty/>
);
};
removePlace = async (place_id) => {
try {
var user = firebase.auth().currentUser;
uid = user.uid;
const places = await AsyncStorage.getItem('places');
let placesFav = JSON.parse(places);
placesItems = placesFav.filter(function(e){ return e.place_id !== place_id && e.userId == uid })
await AsyncStorage.setItem('places', JSON.stringify(placesItems));
this.setState({
...this.state,
places: placesItems || []
});
} catch(error) {
}};
render () {
return (
<List>
<ListItem itemDivider>
<Text>{Strings.ST1}</Text>
</ListItem>
<FlatList
data={this.state.places}
refreshing="true"
renderItem={({item, index}) =>
<ListItem style={{paddingLeft: 0, marginLeft: 0, backgroundColor:'#FFF', opacity: 1, borderColor: 'rgba(0,0,0,0.05)', borderBottomWidth: 1}} onPress={() => this.PlaceDetails(item)} >
<Thumbnail rounded size={80} source={{ uri: ConfigApp.URL+'images/'+item.place_image }} style={{paddingLeft: 10, marginLeft: 10}} />
<Body style={{paddingLeft: 0, marginLeft: 0}}>
<Text numberOfLines={2} style={{fontSize: 14, marginBottom: 3}}>
{item.place_name}
</Text>
</Body>
<Right>
<TouchableOpacity onPress={this.removePlace.bind(this, item.place_id)} activeOpacity={1}>
<Text note>
<Icon name="close" style={{fontSize: 19}}/>
</Text>
</TouchableOpacity>
</Right>
</ListItem>
}
keyExtractor={(item, index) => index.toString()}
ListFooterComponent={this.renderFooterPlaces}
/>
</List>
)
}
async fetchPlaces () {
var user = firebase.auth().currentUser;
uid = user.uid;
let placesJSON= await AsyncStorage.getItem('places');
let placesFav = JSON.parse(placesJSON);
placesItems = placesFav.filter(function(e){
return e.userId == uid
})
const placesArray = placesItems || [];
this.setState({
...this.state,
places: placesArray
});
}
}
export default withNavigation(PlaceFav);
I do not have much knowledge yet in React in Javascript and php, I do not know what this error means and I have searched for answers without success.
I don't know if what I show is enough for you to help me
I finally discovered the mistake, a beginner's mistake
I explain it for if another user happens the same as me.
The problem was that I was not editing the Backend code. I mean that I am working on the project locally and the Backend is on a server.
I modified the code in my local files, but it did not upload the updates to the server
This was why the messages from the application were not sent
I hope this can help someone else, and it makes me think that you have to check all the possible errors before looking for help and solution.
Thanks to this wonderful site
Related
I'm quit new in React native but I would like to set up Google login but what I did didn't seem to work.
(That will be a long post haha )
For Google Login:
I tried several tutorials on YouTube (this one for example: https://www.youtube.com/watch?v=DN9dQ_6ezvA)
"Request is missing required authentication credential. Expected OAuth
2 access token, login cookie or other valid authentication credential.
See
https://developers.google.com/identity/sign-in/web/devconsole-project."
I tried a lot of thing but it's really hard for me. So if someone could give me some help? Thanks you in advance guys, I continue the research on my side
Here is my code:
WebBrowser.maybeCompleteAuthSession();
export default function GoogleFunc({largeur}) {
const fontRegular = require("../../assets/Manrope-Regular.ttf");
const fontBold = require("../../assets/Manrope-Bold.ttf");
const [fontsLoaded] = useFonts({
ManropeRegular: fontRegular,
ManropeBold: fontBold,
});
const [accessToken, setAccessToken] = React.useState();
const [userInfo, setUserInfo] = React.useState();
const [request, response, prompAsync] = Google.useIdTokenAuthRequest({
androidClientId:
"ANDROID_CLIENT_ID",
iosClientId:
"CLIENT_CLIENT_ID",
clientId:
"CLIENT_ID",
});
React.useEffect(() => {
if (response?.type === "success") {
console.log("response: ", response.params);
setAccessToken(response.params.id_token);
accessToken && fetchUserInfo();
}
}, [response, accessToken]);
async function fetchUserInfo() {
console.log("test222");
let response = await fetch("https://www.googleapis.com/userinfo/v2/me", {
headers: {Authorization: `Bearer ${accessToken}`},
});
const useInfo = await response.json();
console.log("useinfo: ", useInfo);
setUserInfo(useInfo);
}
const ShowUserInfo = () => {
if (userInfo) {
console.log("userinfooofofof: ", userInfo);
return (
<View style={styles.userInfo}>
<Image source={{uri: userInfo.picture}} style={styles.profilePic} />
<Text>Welcome {userInfo.name}</Text>
<Text>{userInfo.email}</Text>
</View>
);
}
};
return (
<View style={styles.container}>
{userInfo && <ShowUserInfo />}
{userInfo == null && (
<>
<TouchableOpacity
style={[styles.googleBtn, {width: largeur}]}
disabled={!request}
onPress={() => {
prompAsync();
}}
>
<Image
style={{
height: height * 0.024,
width: width * 0.057,
left: width * 0.035,
top: height * 0.013,
}}
source={require("../../assets/images/google-logo.png")}
/>
<Text
style={{
textAlign: "center",
fontFamily: "ManropeSemiBold",
fontSize: 17,
color: "#262626",
bottom: height * 0.01,
}}
>
Continuer avec Google
</Text>
</TouchableOpacity>
</>
)}
</View>
);
}
For Facebook:
I tried to set up the login with / without firebase but I already got the same issue : an error ...
I'm trying to solve it since last week but I don't understand how can i fix these problems ...
Here's my code without Firebase:
import React, {useState} from "react";
import {
StyleSheet,
Text,
View,
Image,
TouchableOpacity,
ActivityIndicator,
} from "react-native";
import * as Facebook from "expo-facebook";
export default function FacebookFunc() {
const [isLoggedin, setLoggedinStatus] = useState(false);
const [userData, setUserData] = useState(null);
const [isImageLoading, setImageLoadStatus] = useState(false);
async function faceookLogIn() {
try {
await Facebook.initializeAsync({
appId: "APP ID",
});
const {type, token, expirationDate, permissions, declinedPermissions} =
await Facebook.logInWithReadPermissionsAsync({
permissions: ["public_profile"],
});
if (type === "success") {
// Get the user's name using Facebook's Graph API
const response = await fetch(
`https://graph.facebook.com/me?access_token=${token}`
);
Alert.alert("Logged in!", `Hi ${(await response.json()).name}!`);
} else {
// type === 'cancel'
}
} catch ({message}) {
alert(`Facebook Login Error: ${message}`);
}
}
logout = () => {
setLoggedinStatus(false);
setUserData(null);
setImageLoadStatus(false);
};
return isLoggedin ? (
userData ? (
<View style={styles.container}>
<Image
style={{width: 200, height: 200, borderRadius: 50}}
source={{uri: userData.picture.data.url}}
onLoadEnd={() => setImageLoadStatus(true)}
// GERER QUAND MARCHERA
/>
<ActivityIndicator
size={"large"}
color={"#0000ff"}
animating={!isImageLoading}
style={{position: "absolute"}}
/>
<Text style={{fontSize: 22, marginVertical: 10}}>
Hi {userData.name}!
</Text>
<TouchableOpacity style={styles.logoutBtn} onPress={logout}>
<Text style={{color: "#fff"}}>Logout</Text>
</TouchableOpacity>
</View>
) : null
) : (
<View style={styles.container}>
<TouchableOpacity style={styles.loginBtn} onPress={faceookLogIn}>
<Text style={{color: "#fff", textAlign: "center"}}>
Login with facebook
</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {},
loginBtn: {
backgroundColor: "#4267b2",
paddingVertical: 10,
borderRadius: 10,
width: "95%",
},
logoutBtn: {
backgroundColor: "grey",
includeFontPadding: 10,
paddingHorizontal: 20,
borderRadius: 20,
position: "absolute:",
bottom: 0,
marginBottom: 200,
},
});
And here my code when I trying with Firebase:
The error:
Possible Unhandled Promise Rejection (id: 0):
TypeError: null is not an object (evaluating 'LoginManager.logInWithPermissions')
The code:
import React from "react";
import {LoginManager, AccessToken} from "react-native-fbsdk-next";
import {
StyleSheet,
View,
Text,
Image,
TouchableOpacity,
Button,
} from "react-native";
import {
getAuth,
signInWithCredential,
FacebookAuthProvider,
} from "firebase/auth";
import "expo-dev-client";
import app from "./firebaseSetup";
export default function App() {
const SignInWithFB = async () => {
const result = await LoginManager.logInWithPermissions([
"public_profile",
"email",
]);
if (result.isCancelled) {
throw new Error("User cancelled login");
}
const data = await AccessToken.getCurrentAccessToken();
if (!data) {
throw new Error("Something went wrong obtaining access token");
}
const auth = getAuth(app);
const credential = FacebookAuthProvider.credential(data.accessToken);
const user = await signInWithCredential(auth, credential);
console.log(user);
};
return (
<View>
<Button title="Sign in with facebook" onPress={SignInWithFB}></Button>
</View>
);
}
const styles = StyleSheet.create({});
I initialize my firebaseSetup like this:
import {initializeApp} from "firebase/app";
// Initialize Firebase
const firebaseConfig = {
apiKey: "",
authDomain: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
measurementId: "",
};
const app = initializeApp(firebaseConfig);
export default app;
I continue my research by my side but if someone could help me with this problem (which is probably stupid), thanks you in advance...
PS: There is the error for Facebook without firebase:
Facebook Login Error: undefined is not an object (evaluating'_ExponentFacebook.default.InitializeAsync')
You have to use expo auth session to implement oAuth in Expo
import React,{useState} from 'react';
import { useNavigation } from "#react-navigation/native";
import Fontisto from '#expo/vector-icons/Fontisto';
import { TouchableOpacity,StyleSheet, Alert } from 'react-native';
import * as WebBrowser from 'expo-web-browser';
import * as Facebook from 'expo-auth-session/providers/facebook';
import {makeRedirectUri, ResponseType } from 'expo-auth-session';
import { useDispatch } from "react-redux";
WebBrowser.maybeCompleteAuthSession();
export default function FacebookAuth(){
const [isLoading, setIsLoading] = useState(false);
const navigation = useNavigation();
const dispatch = useDispatch();
const [request, response, promptAsync] = Facebook.useAuthRequest({
responseType: ResponseType.Token,
clientId: 'YOUR_CLIENT_ID',
scopes: ['public_profile', 'email'],
redirectUri: makeRedirectUri({ useProxy: true })
},
{ useProxy: true });
React.useEffect(() => {
if (response?.type === 'success') {
setIsLoading(true);
const accessToken = response.authentication.accessToken;
console.log(accessToken);
}
}, [response]);
return(
<>
<TouchableOpacity disabled={!request} style={styles.socialLoginButton}
onPress={() => {
promptAsync();
}}
>
<Fontisto name='facebook' color={'white'} size={25}/>
</TouchableOpacity>
</>
)
}
const styles = StyleSheet.create({
socialLoginButton:{
margin:3,
backgroundColor:'blue',
padding:10,
borderRadius:50,
width:50,
height:50,
justifyContent:'center',
alignItems:'center',
margin:10,
}
})
Here's the code for it, you have to configure it according to your needs.
here's the link for expo auth session. - here
For login with Google, I think the problem lies with this code:
React.useEffect(() => {
if (response?.type === "success") {
setAccessToken(response.params.id_token);
accessToken && fetchUserInfo();
}
}, [response, accessToken]);
You use the id_token from the response, and you should be using the access token. Also, I think you could split this into two useEffect methods:
React.useEffect(() => {
if (response?.type === "success") {
setAccessToken(response.params.access_token);
}
}, [response]);
React.useEffect(() => {
fetchUserInfo();
}, [accessToken]);
The other effect will trigger only when the state of accessToken changes. If it's possible that you change the state to an empty value then you should retain the null check.
As for Facebook and Firebase issues — are you sure you followed all the required setup for these libraries? Just skimming through the documentation shows that there are quite a few things that should be configured before you can call the libs. From your error messages, it seems that the libraries are not configured and initialized properly.
So I am here to ask if there is a method to use firebase with real-time database in 1 apps.
My login already worked using Firestore.
This is my code that is storing 1 text to my Firestore data, Its worked too.
I want to change it to real-time database whenever there a new data inserted, but still have the id user logged to my react-native app
The point is I want to use Realtime Database instead of Firestore.
Login as Firestore, Save data as Realtime Database
import React, { useEffect, useState } from 'react'
import { FlatList, Keyboard, Text, TextInput, TouchableOpacity, View } from 'react-native'
import styles from './styles';
import { firebase } from '../../firebase/config'
export default function HomeScreen(props) {
const [entityText, setEntityText] = useState('')
const [entities, setEntities] = useState([])
const entityRef = firebase.firestore().collection('entities')
const userID = props.extraData.id
useEffect(() => {
entityRef
.where("authorID", "==", userID)
.orderBy('createdAt', 'desc')
.onSnapshot(
querySnapshot => {
const newEntities = []
querySnapshot.forEach(doc => {
const entity = doc.data()
entity.id = doc.id
newEntities.push(entity)
});
setEntities(newEntities)
},
error => {
console.log(error)
}
)
}, [])
const onAddButtonPress = () => {
if (entityText && entityText.length > 0) {
const timestamp = firebase.firestore.FieldValue.serverTimestamp();
const data = {
text: entityText,
authorID: userID,
createdAt: timestamp,
};
entityRef
.add(data)
.then(_doc => {
setEntityText('')
Keyboard.dismiss()
})
.catch((error) => {
alert(error)
});
}
}
const renderEntity = ({item, index}) => {
return (
<View style={styles.entityContainer}>
<Text style={styles.entityText}>
{index}. {item.text}
</Text>
</View>
)
}
return (
<View style={styles.container}>
<View style={styles.formContainer}>
<TextInput
style={styles.input}
placeholder='Add new entity'
placeholderTextColor="#aaaaaa"
onChangeText={(text) => setEntityText(text)}
value={entityText}
underlineColorAndroid="transparent"
autoCapitalize="none"
/>
<TouchableOpacity style={styles.button} onPress={onAddButtonPress}>
<Text style={styles.buttonText}>Add</Text>
</TouchableOpacity>
</View>
{ entities && (
<View style={styles.listContainer}>
<FlatList
data={entities}
renderItem={renderEntity}
keyExtractor={(item) => item.id}
removeClippedSubviews={true}
/>
</View>
)}
</View>
)
}
Can someone help me and tell me how to do that?
thanks
I am struggling with useFocusEffect or useEffect. I am trying to fetch data when user navigate to the user profile this is working but when user navigate back to the profile i have a duplicate posts! I've been working on this problem for 3 days. Please any ideas.
This is the code:
import React, { useState, useEffect, useRef } from "react";
import {
View,
Text,
FlatList,
Image,
TouchableOpacity,
Animated,
ActivityIndicator,
} from "react-native";
import APIKIT from "../../../services/APIKit";
import styles from "./UserPostStyle";
import moment from "moment";
import { MaterialCommunityIcons, FontAwesome } from "#expo/vector-icons";
import { useNavigation } from "#react-navigation/native";
import { useFocusEffect } from "#react-navigation/native";
const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);
moment.updateLocale("en", {
relativeTime: {
future: "in %s",
past: "%s ago",
s: "Just now",
ss: "%ss",
m: "1m",
mm: "%dm",
h: "1h",
hh: "%dh",
d: "1d",
dd: "%dd",
M: "1mo",
MM: "%dmo",
y: "1y",
yy: "%dy",
},
});
export function UserPosts({ ...props }) {
const [userPosts, setUserPosts] = useState([]);
const [posts, setPosts] = useState([]); // Array with the posts objects
let postsArray = useRef(posts).current; // Auxiliar array for storing posts before updating the state. Pd: this will not re-render the component as it is a reference
const [page, setPage] = useState(1);
const [lastPage, setLastPage] = useState(0);
const [loadingMore, setLoadingMore] = useState(false);
const navigation = useNavigation();
useFocusEffect(
React.useCallback(() => {
if (props.userId) {
fetchPosts();
}
return () => {};
}, [props.userToken, props.userId, page])
);
// useEffect(() => {
// console.log(" -----------useEffect page", page);
// console.log(" -----------useEffect lastPage", lastPage);
// let mounted = true;
// if (mounted && props.userId) {
// fetchPosts();
// }
// return () => {
// console.log("return useEffect page", page);
// console.log("return useEffect lastPage", lastPage);
// mounted = false;
// };
// }, [props.userToken, props.userId, page]);
const fetchPosts = async () => {
if (props.userToken !== null) {
const config = {
headers: { Authorization: `Bearer ${props.userToken}` },
};
APIKIT.get(`/user/posts/${props.userId}?page=${page}`, config)
.then((response) => {
let posts = [];
const { data } = response;
setLastPage(data.userPosts.last_page);
for (let userPost of data.userPosts.data) {
let post = {};
post["id"] = userPost.id;
post["location_coordinate"] = userPost.location_coordinate;
post["location_icon"] = userPost.location_icon;
post["location_id"] = userPost.location_id;
post["location_title"] = userPost.location_title;
post["location_vicinity"] = userPost.location_vicinity;
post["post_body"] = userPost.post_body;
post["created_at"] = moment(userPost.created_at).fromNow(true);
post["user_id"] = userPost.user_id;
posts.push(post);
}
posts.forEach((newPost) => {
// Add the new fetched post to the head of the posts list
postsArray.unshift(newPost);
});
setPosts([...postsArray]); // Shallow copy of the posts array to force a FlatList re-render
setUserPosts((prevPosts) => [...prevPosts, ...posts]);
setLoadingMore(false);
if (page === lastPage) {
setLoadingMore(false);
return;
}
})
.catch((e) => {
console.log("There is an error eccured while getting the posts ", e);
setLoadingMore(false);
});
}
};
const Item = ({
post_body,
id,
location_coordinate,
location_icon,
location_title,
location_vicinity,
location_id,
created_at,
}) => (
<View style={styles.postContainer}>
<TouchableOpacity
onPress={() => {
navigation.navigate("PostDetailsScreen", {
location_coordinate: JSON.parse(location_coordinate),
userAvatar: props.userAvatar,
username: props.username,
name: props.name,
created_at: created_at,
post_body: post_body,
location_title: location_title,
location_vicinity: location_vicinity,
location_icon: location_icon,
location_id: location_id,
});
}}
>
<View style={styles.postHeader}>
<Image
style={styles.userAvatar}
source={
props.userAvatar
? { uri: props.userAvatar }
: require("../../../../assets/images/default.jpg")
}
/>
<View style={styles.postUserMeta}>
<View style={{ flexDirection: "row", alignItems: "center" }}>
<Text style={styles.name}>{props.name}</Text>
<Text style={styles.createdAt}>{created_at}</Text>
</View>
<Text style={styles.username}>#{props.username}</Text>
</View>
</View>
<View style={styles.postContent}>
<View>
<Text style={styles.postBody}>{post_body}</Text>
</View>
</View>
</TouchableOpacity>
<TouchableOpacity
style={styles.locationInfoContainer}
onPress={() => {
navigation.navigate("PostPlaceDetailsScreen", {
location_coordinate: JSON.parse(location_coordinate),
userAvatar: props.userAvatar,
username: props.username,
name: props.name,
created_at: created_at,
post_body: post_body,
location_title: location_title,
location_vicinity: location_vicinity,
location_icon: location_icon,
location_id: location_id,
});
}}
>
<View style={styles.locationInfo}>
<Image style={styles.locationIcon} source={{ uri: location_icon }} />
<View style={styles.locationMeta}>
<Text style={styles.locationTitle}>{location_title}</Text>
</View>
</View>
</TouchableOpacity>
<View
style={{
borderWidth: 1,
borderColor: "#F2F2F2",
marginTop: 10,
marginBottom: 10,
}}
/>
<View style={styles.postFooter}>
<TouchableOpacity>
<MaterialCommunityIcons name="comment" size={24} color="#999999" />
</TouchableOpacity>
<TouchableOpacity>
<FontAwesome name="star" size={24} color="#999999" />
</TouchableOpacity>
{/* After fav color #FFBE5B */}
<TouchableOpacity>
<MaterialCommunityIcons
name="dots-horizontal"
size={24}
color="#999999"
/>
</TouchableOpacity>
</View>
</View>
);
const renderItem = ({ item }) => (
<Item
location_coordinate={item.location_coordinate}
post_body={item.post_body}
id={item.id}
location_id={item.location_id}
location_icon={item.location_icon}
location_title={item.location_title}
location_vicinity={item.location_vicinity}
created_at={item.created_at}
/>
);
const emptyPosts = () => {
return (
<View style={styles.noPostsMessageContainer}>
<View style={styles.messageContainer}>
<Image
style={styles.noPostMessageImage}
source={require("../../../../assets/images/Logo.png")}
/>
<Text style={styles.noPostMessageText}>No posts yet!</Text>
</View>
</View>
);
};
const handleLoadingMore = () => {
if (page === lastPage) {
return;
}
setPage(page + 1);
setLoadingMore(true);
};
return (
<View style={styles.userPostContainer}>
<AnimatedFlatList
showsVerticalScrollIndicator={false}
data={userPosts}
renderItem={renderItem}
keyExtractor={(item) => item.id.toString()}
contentContainerStyle={{
paddingTop: 250,
paddingBottom: 100,
}}
scrollEventThrottle={16}
onScroll={props.scrolling}
ListEmptyComponent={emptyPosts}
onEndReachedThreshold={0.5}
onMomentumScrollEnd={() => handleLoadingMore()}
ListFooterComponent={
loadingMore && <ActivityIndicator size="large" animating />
}
/>
</View>
);
}
FlatList
return (
<View style={styles.userPostContainer}>
<AnimatedFlatList
showsVerticalScrollIndicator={false}
data={userPosts}
renderItem={renderItem}
keyExtractor={(item) => item.id.toString()}
contentContainerStyle={{
paddingTop: 250,
paddingBottom: 100,
}}
scrollEventThrottle={16}
onScroll={props.scrolling}
ListEmptyComponent={emptyPosts}
onEndReachedThreshold={0.5}
onMomentumScrollEnd={() => handleLoadingMore()}
ListFooterComponent={
loadingMore && <ActivityIndicator size="large" animating />
}
/>
</View>
);
handleLoadingMore function
const handleLoadingMore = () => {
if (page === lastPage) {
return;
}
setPage(page + 1);
setLoadingMore(true);
};
I think the problom is when the user navigate back to the profile the state still the same and useFocusEffect fetching the same data again.
setUserPosts((prevPosts) => [...prevPosts, ...posts]);
Thanks for you help.
I have never used this hook from "react-navigation" but in the doc it says:
Sometimes we want to run side-effects when a screen is focused. A side
effect may involve things like adding an event listener, fetching
data, updating document title, etc. While this can be achieved using
focus and blur events, it's not very ergonomic.
So, every time you focus an specific route the code will run.
I am trying to fetch data when user navigate to the user profile this
is working but when user navigate back to the profile i have a
duplicate posts!
What you are doing is wrong because you are not paginating your fetches, I mean, you will need a "pointer" to the last post you fetched... with this you will avoid to fetch the data you already have. Also, the user experience will be pretty faster, as you will have lighter responses from your DB.
Anyways, I suggest you to run this code in the "useEffect" hook from React Native and try to implement a db listener or an inifinite scroll with pagination. This will not work when you focus the screen, but you will be able to fetch data every time the user refresh the FlatList, just like Instagram, Twitter, Netflix...
Take a look on this: https://aboutreact.com/react-native-flatlist-pagination-to-load-more-data-dynamically-infinite-list/
If you really need to fetch data when you focus the specific route, just implement a pagination (save in your component state an index to the last post you fetched).
UPDATE
Sorry, I didn't see that you was doing the pagination in your code. It might be a problem when you update the state of your component...
Try something like that:
const [posts, setPosts] = useState([]); // Array with the posts objects
let postsArray = useRef(posts).current; // Auxiliar array for storing posts before updating the state. Pd: this will not re-render the component as it is a reference
const loadMorePosts = () => {
// ... stuff
// const newPosts = Fetch posts
newPosts.forEach((newPost) => {
// Add the new fetched post to the head of the posts list
postsArray.unshift(newPost);
})
// The last post will be at the top of the list
setPosts([...postsArray]); // Shallow copy of the posts array to force a FlatList re-render
}
// setUserPosts((prevPosts) => [...prevPosts, ...posts]);
I used https://www.npmjs.com/package/react-native-dynamodb to implement DynamoDB access for my project. I used the same exact code as that website.
The only thing is, I can't see how my .init() method is giving me: Unresolved function or method init() upon hovering over it (I'm using the WebStorm IDE by the way). I believe that's the reason why my app won't run. Below is the code as well as the error I'm getting in the simulator.
Error in iOS Simulator
Here's my .js file:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { ScrollView, Text, View, Button } from 'react-native';
import { logout } from '../redux/actions/auth';
import DropdownMenu from 'react-native-dropdown-menu';
import Icon from './Icon';
import DynamoDB from 'react-native-dynamodb';
let dynamodb = DynamoDB.init({
credentials: {
AccessKeyId: 'Some key',
SecretKey: 'Some key'
}
// region: 'us-east-1' - default, optional
// version: '20120810' - default, optional
})
dynamodb.table('user_choice').PutItem(
{
name: 'Jack Sparrow',
age: 30,
captain: true
},
{
ConditionExpression: "last_movie <> :movie",
ExpressionAttributeValues: {
":movie": {"S": "Pirates of the Caribbean: On Stranger Tides"}
}
})
.then((response) => console.log(response)) // AWS object response
.catch((error) => {
console.log(error)
})
class Secured extends Component {
render() {
var data = [["Literacy Leaders"], ["Wrestling Camp"], ["Screenplay Writing"], ["Panetarium Workshop"]];
return(
<ScrollView style={{padding: 20}}>
<Icon/>
<Text style={{fontSize: 27}}>
{`Welcome ${this.props.username}`}
</Text>
<View style={{flex: 1}}>
<DropdownMenu style={{flex: 1}}
bgColor={"purple"} //the background color of the head, default is grey
tintColor={"white"} //the text color of the head, default is white
selectItemColor={"orange"} //the text color of the selected item, default is red
data={data}
maxHeight={410} // the max height of the menu
handler={(selection, row) => alert(data[selection][row])} >
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}} >
</View>
</DropdownMenu>
</View>
<View style={{margin: 20}}/>
<Button onPress={(e) => this.userLogout(e)} title="Logout"/>
</ScrollView>
);
}
}
const mapStateToProps = (state, ownProps) => {
return {
username: state.auth.username
};
}
const mapDispatchToProps = (dispatch) => {
return {
onLogout: () => { dispatch(logout()); }
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Secured);
I checked the source code of react-native-dynamodb, seems DynamoDB is not exported as default but a named export.
Try import it like this:
import { DynamoDB } from 'react-native-dynamodb';
I would like to have two text fields:
one that accepts a title
another that accepts a body (i.e. more text)
...and a submit button:
that saves the title and body that was entered, when clicked
I have researched TextInput, AsyncStorage, TouchableHighlight and Navigator components as well as a bunch of react-native tutorials. I can't seem to find any consistency - not even from the react-native docs.
Here is what I have so far:
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
AsyncStorage,
TextInput,
TouchableHighlight
} from 'react-native';
class PostAndSave extends Component {
constructor(props) {
super(props);
this.state = {
messageTitle: '',
messageBody: ''
}
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Walker app
</Text>
<TextInput
placeholder="Title"
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChange={(event) => this.setState({messageTitle: event.nativeEvent.text})}
value={this.state.messageTitle} />
<TextInput
placeholder="Body"
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChange={(event) => this.setState({messageBody: event.nativeEvent.text})}
value={this.state.messageBody} />
<TouchableHighlight onPress={this._onPressButton} style={styles.button}>
<Text style={styles.buttonText}>See all posts</Text>
</TouchableHighlight>
</View>
);
}
}
// styles here
AppRegistry.registerComponent('PostAndSave', () => PostAndSave);
I can type into the input fields but cannot figure AsyncStorage out, or how to post new messages as opposed to the overwriting the existing one. I'm mainly looking for help in that area - below I have posted my goal incase the question of why I want to do this comes up.
Goal:
The saved 'post' should then be printed to a view, where it can be pressed (tapped?) to display the contents of the body.
Each time a title and body are submitted they should be saved as a new 'post' and not overwritten.
If you want to use Async for this you'll need a function to save the data:
_onPressButton () {
// Get the data
let title = this.state.messageTitle
let message = this.state.messageBody
// Retrieve the existing messages
AsyncStorage.getItem('messages', (res) => {
var messages
// If this is the first time, set up a new array
if (res === null) {
messages = []
}else {
messages = JSON.parse(res)
}
// Add the new message
messages.push({
title: title,
message: message
})
// Save the messages
AsyncStorage.setItem('messages', JSON.stringify(messages), (res) => {})
}
}
And you'll want to bind this to your instance:
<TouchableHighlight onPress={this._onPressButton.bind(this)} style={styles.button}>
And to retrieve your messages for use later:
AsyncStorage.getItem('messages', (res) => {
this.setState({
messages: res
})
})