Array of objects do not render using setState and map - javascript

I am using typescript in a react-native project, and would like to render an array of objects that come from a query using AWS-Amplify, using the map function.
I use setState (here setTracks) to declare my state.
While it logs well in the console, the map function does not render anything.
Here is the code:
import {useEffect, useState} from 'react';
import {
ScrollView,
SafeAreaView,
StyleSheet,
Image,
TouchableWithoutFeedback,
ImageBackground,
Dimensions
} from "react-native";
import EditScreenInfo from '../components/EditScreenInfo';
import { Text, View } from '../components/Themed';
import Amplify from 'aws-amplify'
import config from './aws-exports'
Amplify.configure(config)
import { API, graphqlOperation } from 'aws-amplify'
import { listTracks } from '../src/graphql/queries'
export default function TabTwoScreen() {
const [tracks, setTracks] = useState<Array>([])
//const [tracks, setTracks] = useState([])
useEffect(() => {
fetchTracks()}, [])
async function fetchTracks() {
try {
const trackData = await API.graphql(graphqlOperation(listTracks))
console.log('trackData:', trackData.data.listTracks.items)
setTracks([trackData])
console.log('trackdata is: ', tracks)
} catch (err) {
console.log('error fetching tracks...', err)
}
};
return (
<SafeAreaView style={styles.container}>
{
tracks.map((track, index) => (
<View key={index} style={styles.item}>
<Text style={styles.name}>{track.song}</Text>
<Text style={styles.description}>{track.artist}</Text>
<Text style={styles.city}>{track.songUrl}</Text>
</View>
))
}
</SafeAreaView>
)
}```

Related

how to call provider function in child with react native?

I have two components. One is the provider and the second is a child. Now I want to use the function of provider in the child but with my current approach, it says that function is undefined. Can you see what I'm doing wrong?
Here is the code below.
import React from 'react';
import { View, TouchableOpacity, Text } from 'react-native';
const MyProvider = (props) => {
const { children } = props;
const handlePress = () => {
console.log("Provider component function called!");
};
return (
<View>
{children}
</View>
);
};
const NoLocationAccess = (props) => {
const { handlePress } = props;
console.log("handlePress : ",handlePress)
return (
<TouchableOpacity onPress={handlePress}>
<Text>I am the child component</Text>
</TouchableOpacity>
);
};
export default NoLocationAccess;
I have tried provider.wrapper. that made things more problematic.
To call a function, that is defined in the provider, from the child you need too pass it down as a prop.
Here the modified Code:
import React from 'react';
import { View, TouchableOpacity, Text } from 'react-native';
const MyProvider = (props) => {
const { children } = props;
const handlePress = () => {
console.log("Provider component function called!");
};
return (
<View>
{React.Children.map(children, (child) => {
return React.cloneElement(child, { handlePress });
})}
</View>
);
};
const NoLocationAccess = (props) => {
const { handlePress } = props;
console.log("handlePress : ",handlePress)
return (
<TouchableOpacity onPress={() => handlePress()}>
<Text>I am the child component</Text>
</TouchableOpacity>
);
};
export default NoLocationAccess;
Try it
It took me a while. but I have done this high-order component. this idea came to mind with the redux connect method. so took that approach and created a higher-order component. that works flawlessly.
Here is the solution.
High-Order Component.
import React from 'react';
import { View, TouchableOpacity, Text } from 'react-native';
const MyProvider = (props) => {
class GPSComponent extends React.Component {
componentDidMount() {
}
requestPermissions= async()=> {
console.log("i is called",this.props.userCurrentLocation)
}
render() {
return <WrappedComponent
requestPermissions={this.requestPermissions}
{...this}
/>;
}
}
return GPSComponent;
};
child component.
import React from 'react';
import { View, TouchableOpacity, Text } from 'react-native';
import MyProvider from "./MyProvider"
const NoLocationAccess = (prop) => {
const { requestPermissions } = prop;
console.log("requestPermissions ",requestPermissions)
return (
<TouchableOpacity onPress={requestPermissions}>
<Text>I am the child component</Text>
</TouchableOpacity>
);
};
export default MyProvider(NoLocationAccess);

Next page after loads in React Native

I'm newbie in React-native , I've just confused on how can I go to next page when the Google API successfully load to my app, mostly in the internet they used onPress but I don't have any onPress just to trigger the event instead i've implement after it successfully login data and will trigger the event, how should I do it?
From Login > Home
Apps.js
import React from 'react';
import Login from './components/login'
import SplashScreen from 'react-native-splash-screen';
const App = () => {
React.useEffect(() =>{
SplashScreen.hide()
},[])
return (
<Login/>
)
}
export default App;
Login.js
import React, { Component } from 'react';
import { View, StyleSheet, ToastAndroid, Button ,Text,Image} from "react-native";
import {
GoogleSignin,
GoogleSigninButton,
statusCodes,
} from '#react-native-community/google-signin';
GoogleSignin.configure({
webClientId: 'testttttttt.........apps.googleusercontent.com',
offlineAccess: true,
});
class Login extends Component {
constructor(props){
super(props)
this.state={
userGoogleInfo : {},
loaded: false
}}
signIn = async () => {
try {
console.log("Processing");
await GoogleSignin.hasPlayServices();
const userInfo = await GoogleSignin.signIn();
this.setState({
userGoogleInfo : userInfo,
loaded : true
})
// after this it goes to another page Home.js -----------------------------------------<<<<<<<<<
} catch (error) {
if (error.code === statusCodes.SIGN_IN_CANCELLED) {
console.log("e 1");
} else if (error.code === statusCodes.IN_PROGRESS) {
console.log("e 2");
} else if (error.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
console.log("e 3");
} else {
console.log(error.message);
}
}
};
render() {
return (
<View style={styles.container}>
<GoogleSigninButton
style={{ width: 222, height: 48 }}
size={GoogleSigninButton.Size.Wide}
color={GoogleSigninButton.Color.Dark}
onPress={this.signIn}
/>
{this.state.loaded ?
<View>
<Text>{this.state.userGoogleInfo.user.name}</Text>
<Text>{this.state.userGoogleInfo.user.email}</Text>
<Image
style={{ width: 100, height: 100 }}
source={{uri: this.state.userGoogleInfo.user.photo}}
/>
</View>
: <Text>Not SignedIn</Text> }
</View>
);
}
}
const styles = StyleSheet.create({
container:{
flex:1,
backgroundColor:'#000000',
padding:15,
},
});
export default Login;
Home.js
import React from 'react';
import Login from './components/login'
import SplashScreen from 'react-native-splash-screen';
import { View,Text} from "react-native";
const App = () => {
React.useEffect(() =>{
SplashScreen.hide()
},[])
return (
<View>
<Text>fsaf</Text>
</View>
)
}
export default App;
You can use React Navigation
And once you have a proper setup use push method
navigation.push('YourView')
First, you need to add a navigation component to your project. The React Native documentation has a section about it with some libraries suggestions.
The React Navigation is hugely used and has the CommonActions that resolve your problem. After installing the React Navigation you can see this section on the documentation to dispatch the CommonActions to navigate to the Home screen after login success on your try...catch.

Display variable inside my render React Native

I was trying to display data from a fetch function to my render app in react native.
I was able to get the data from my fetch but i am not able to display it on the app..
this is my code:
import React from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
export default function App() {
const fetchDatos = async () => {
return fetch('http://localhost:8000/api/consulta').then(response => {
return response.json();
})
.then(responseJson => {
var Nombre = responseJson.Participante.InfoParticipante['#attributes'].Nombre;
});
}
return (
<View>
<Button
title='press me'
onPress={fetchDatos}
/>
<Text>{Nombre}</Text>
</View>
);
}
As you can see in the code above I get the data stored in the var ''Nombre'' and I am trying the display it in the app but it's telling me Uncaught ReferenceError: Nombre is not defined
Does anyone know how to fix this, I would appreciate it a lot!
This will work
import React,{useState} from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
export default function App() {
const [nombre,setNombre]=useState()
const fetchDatos = () => {
return fetch('http://localhost:8000/api/consulta').then(response => {
return response.json();
})
.then(responseJson => {
setNombre(responseJson.Participante.InfoParticipante['#attributes'].Nombre);
});
}
return (
<View>
<Button
title='press me'
onPress={fetchDatos}
/>
<Text>{nombre}</Text>
</View>
);
}

FlatList does not render any text in react-native

I'm fairly new to react native and redux and was trying to render the library title from a JSON file in a flat list using redux, but my FlatList component does not render anything on the screen.
here's my code :
LibraryList.js
import React, { Component } from "react";
import { FlatList } from "react-native";
import { connect } from "react-redux";
import ListItem from "./ListItem";
class LibraryList extends Component {
renderItem(library) {
return <ListItem library={library} />;
}
render() {
return (
<FlatList
data={this.props.libraries}
renderItem={this.renderItem}
keyExtractor={library => library.id}
/>
);
}
}
const mapStateToProps = state => {
return { libraries: state.libraries };
};
export default connect(mapStateToProps)(LibraryList);
ListItem.js
import React, { Component } from "react";
import { Text } from "react-native";
import { CardSection } from "./common";
class ListItem extends Component {
render() {
return (
<CardSection>
<Text>{this.props.library.title}</Text>
</CardSection>
);
}
}
export default ListItem;
App.js
import React from "react";
import { View } from "react-native";
import { Provider } from "react-redux";
import { createStore } from "redux";
import reducers from "./reducers";
import { Header } from "./components/common";
import LibraryList from "./components/LibraryList";
const App = () => {
return (
<Provider store={createStore(reducers)}>
<View>
<Header headerText="Tech Stack" />
<LibraryList />
</View>
</Provider>
);
};
export default App;
The JSON file is like
[
{
"id": '' ,
"title": '' ,
"description":''
},
{
"id":'' ,
"title":'' ,
"description":''
}
]
I read some solutions for this suggesting changing the renderItem function to something like this
renderItem = ({ library }) => <ListItem library={library} />
still does not work. Can someone help me with this problem?
Thanks.
You have to make your renderItem as an arrow function. Otherwise you have to bind your function inside constructor in order to access function as renderItem={this.renderItem}.
import React, { Component } from 'react';
import { FlatList } from 'react-native';
import { connect } from 'react-redux';
import ListItem from './ListItem';
class LibraryList extends Component {
renderItem = ({ item }) => {
return <ListItem library={item} />
}
render() {
return (
<FlatList
data={this.props.libraries}
renderItem={this.renderItem}
keyExtractor={library => library.id}
/>
);
}
}
const mapStateToProps = state => {
return { libraries: state.libraries };
};
export default connect(mapStateToProps)(LibraryList);
or you can call your renderItem as an arrow function inside render like below
renderItem={(item) => this.renderItem(item)}
but using an arrow function in render creates a new function each time the component renders, which may break optimizations based on strict identity comparison.
Hope this helps you. Feel free for doubts.
In your flatlist try thi s:
<FlatList
data={this.props.libraries}
renderItem={({item, index}) => {
this.renderItems(item); // change this name to renderItems so that it doesnt clash with flatlist default renderItem
}}
/>
Hope it helps. feel free for doubts
You have several approaches to your problem.
Firstly your renderItem should be binded, so either do this
renderItem = (library) => {
or this
renderItem={this.renderItem.bind(this)}
besides the binding problem, flatlist prop renderItem will return to your function an object with this structure
{ item, index }
so in reality your renderItem should be like this
renderItem({ item }){
return <ListItem library={item} />;
}

Variable won't be set inside the fetch function

I am trying to print text content of login.php into the screen via "var result", but the fetch function won't alter value of "var result". How can I set value of result from output of the fetch function?
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
StatusBar,
} from 'react-native';
import Logo from '../components/Logo';
import Form from '../components/Form';
import loginapi from '../apis/loginapi';
var result='noresult';
export default class Login extends Component<{}> {
render() {
login();
return (
<View style={styles.container}>
<Logo/>
<Form/>
<Text>
{result}
</Text>
<Text>
</Text></View>
);
}
}
function login() {
result = fetch('https://www.skateandstrike.com/loginsv/login.php').then((text) => {return text;});
}
const styles = StyleSheet.create({
container : {
backgroundColor:'#f05545',
flex: 1,
alignItems:'center',
justifyContent:'center',
}
});
function myFunction() {
this.setState({ showLoading: false });
}
This is not working too, using setState:
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
StatusBar,
} from 'react-native';
import Logo from '../components/Logo';
import Form from '../components/Form';
import loginapi from '../apis/loginapi';
export default class Login extends Component<{}> {
constructor(){
super();
this.state = {
data:'NoData',
}
}
render() {
login();
return (
<View style={styles.container}>
<Logo/>
<Form/>
<Text>
{this.state.data}
</Text>
</View>
);
}
}
function login() {
fetch('https://www.skateandstrike.com/loginsv/login.php').then(data => this.setState(data));
}
const styles = StyleSheet.create({
container : {
backgroundColor:'#f05545',
flex: 1,
alignItems:'center',
justifyContent:'center',
}
});
function myFunction() {
this.setState({ showLoading: false });
}
Am I using setState in a wrong way? Thanks in advance for your help.
When using the fetch API, I'd recommend using a promise, and you parse it if you are setting the state.
React re-renders on state/props change.
sample code:
fetch(url)
.then(data => data.json()) // if needed
.then(data => this.setState(data))
remember to set state in the constructor.

Categories