Displaying multiple data in react native - react-native

I am pretty new to react native. I am currently grabbing data from my node.js and trying to show all the data I grabbed into my View. In react.js, i did
documnet.getElementById.append().
What is the best way to do it in react native?
my code looks something like this
class GlobalRankings extends Component{
constructor(){
super();
this.state = {
}
this.getGlobalRankings();
}
getGlobalRankings(){
var request = new Request(checkEnvPort(process.env.NODE_ENV) + '/api/global_rankings', {
method: 'GET',
headers: new Headers({ 'Content-Type' : 'application/json', 'Accept': 'application/json' })
});
fetch(request).then((response) => {
response.json().then((data) => {
console.log(data);
for (var i in data.value){
console.log(data.value[i]); //where i grab my data
}
});
}).catch(function(err){
console.log(err);
})
}
render(){
return(
<View style={styles.container}>
// want my data to be here
</View>
)
}
}
Thanks for all the help

You can make an array in state in constructor, this.state = { arr: [] }
Then you assign the data array you get from the response.
fetch(request).then((response) => {
response.json().then((data) => {
this.setState({ arr: data.array });
});
}).catch(function(err){
console.log(err);
});
Then in the component body,
<View style={styles.container}>
{
this.state.arr.map((value, index) => {
return(
<Text key={index}>{value.text}</Text>
);
})
}
</View>

Related

How Can I Use a Component by Functions Response in React Native?

I'm trying to show a Lottie animation if the API response true. Here is my code:
export default class Register extends Component{
constructor(props){
super(props);
this.state = {
//variables
};
}
buttonClick = () =>{
//variables
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({variables})
};
fetch('api_url',requestOptions)
.then((response) => { return response.json() } )
.catch((error) => console.warn("fetch error:", error))
.then((response) => {
console.log(response)
if(response == "true"){
<LottieView
style={styles.success}
source = {require("./lottie/success.json")}
autoPlay = {true}
loop={false}
/>
}
})
}
render(){
return (
//textinputs and buttons
)
}
}
but the animation not showing up. I know it because of LottieView not in "render and return" parts but I don't know how can I fix it.
Add a useState isFetched, default value is false. If response is true, change state to true.
In render add this:
isFetched && (
<LottieView
style={styles.success}
source = {require("./lottie/success.json")}
autoPlay = {true}
loop={false}
/>
)

How to store API response in state And pass this response value to another screen as params in react native

I am new to react native. I have created A screen. Where I am getting response from API. but now I want to store that response in state. and I want to send that value to another screen by navigation params.
my response is like this ->
Array [
Object {
"phpid": 10,
},
]
here is my code
constructor(props) {
super(props);
this.state={
};
}
fetch('https://xuz.tech/Android_API_CI/uploaddata/t_details?query=', {
method: 'POST',
headers: {'Accept': 'application/json, text/plain, */*', "Content-Type": "application/json" },
body: JSON.stringify([{"==some values=="}])
})
.then((returnValue) => returnValue.json())
.then(function(response) {
console.log(response)
return response.json();
render(){
return (
<View style={{flex: 1}}>
color="black" onPress={() => this.props.navigation.navigate("FormItems",{i want to send value to formitems})} />
</View>
)}
Set your state once you receive your response, then use your state as params when navigating. Once your fetch has been resolved:
this.setState({ response: response.json() });
Sending params to another screen is fairly simple, you just need to pass an object as the second parameter to navigate.
this.props.navigation.navigate('FormItems', {
form: this.state.response,
});
The receiving component will then need to read those params:
class DetailsScreen extends React.Component {
render() {
const { navigation } = this.props;
return (
<Text>{JSON.stringify(navigation.getParam('form', 'some default'))}</Text>
}
}
A full explanation on how to use params with react-navigation v4 can be found here: https://reactnavigation.org/docs/4.x/params
Use it like this. first initialise the state and when you get data from api set the data in state and when button press pass the data to new screen in params.
import React, { Component } from 'react';
import { Text, View } from 'react-native';
export default class Example extends Component {
state = {
data: [], // initialize empty state
};
componentWillMount() {
this.requestData();
}
requestData = () =>{
fetch('https://xuz.tech/Android_API_CI/uploaddata/t_details?query=', {
method: 'POST',
headers: {'Accept': 'application/json, text/plain, */*', "Content-Type": "application/json" },
body: JSON.stringify([{"==some values=="}])
})
.then((returnValue) => returnValue.json())
.then(function(response) {
this.setState({
data:response //set data in state here
})
})
}
render() {
return (
<View style={{ flex: 1 }}>
<Button
color="black"
onPress={() =>
this.props.navigation.navigate('FormItems', {
data: this.state.data, // pass data to second screen
})
}
/>
</View>
);
}
}

Invariant Violation in React Native: Text strings must be rendered within a <Text> component

I'm working on a React-Native project with REST APis, and I've currently got an invariant violation error. I've experienced this before, but I can't quite figure out what is causing it and how to fix it. If someone could point me in the right direction, I would really appreciate it! The full error is pictured below, and appears to be referencing a number of tags in the code, so I'm unsure exactly where it is originating. Thank you for reading, and thanks in advance!
The code is here:
import React, { Component } from 'react'
import { View, Text, Image, StyleSheet, FlatList} from 'react-native';
import * as Font from 'expo-font';
import styled from 'styled-components';
import dimensions from '../components/ScreenSize';
import colours from '../components/Colours';
import { Audio } from 'expo-av';
import { TouchableHighlight } from 'react-native-gesture-handler';
const client_id = {Client_ID}
const client_secret = {Client_Secret}
const item = ({item}) => (
<View style={{ flex:1, flexDirection: 'column', margin:1}}>
<TouchableHighlight onPress={() => this.fetchTracks(item.id)}>
<View>
<Text>{item.name}</Text>/>
</View>
</TouchableHighlight>
</View>
)
export default class HomeScreen extends React.Component {
state={
fontsLoaded:false,
}
async componentDidMount() {
await Font.loadAsync({
'montserrat-regular': require('../assets/fonts/Montserrat/Montserrat-Regular.ttf'),
'montserrat-light': require('../assets/fonts/Montserrat/Montserrat-Light.ttf'),
'montserrat-semibold': require('../assets/fonts/Montserrat/Montserrat-SemiBold.ttf'),
'montserrat-bold': require('../assets/fonts/Montserrat/Montserrat-Bold.ttf'),
}
).then(() => this.setState({ fontsLoaded:true }))
this.getToken();
this.setAudio();
}
constructor (props) {
super(props)
this.playbackInstance=null;
this.state = {
playing:false,
token: '',
DATA:[],
};
}
setAudio=() => {
Audio.setAudioModeAsync({
allowsRecordingIOS:false,
interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,
playsInSilentModeIOS: true,
shouldDuckAndroid: true,
interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DO_NOT_MIX,
playThroughEarpieceAndroid: false,
});
}
componentDidCatch(error, info)
{
console.log(error, info.componentStack);
}
getToken = async() =>
{
try
{
const getspotifytoken = await fetch("https://accounts.spotify.com/api/token",
{
method:'POST',
body: `grant_type=client_credentials&client_id=${client_id}&client_secret=${client_secret}`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
const spotifytoken = await getspotifytoken.json();
this.setState({
token: spotifytoken.access_token
});
console.log(this.state.token);
}
catch(err)
{
console.log("Error fetching data", err);
}
}
search = async () => {
try
{
console.log("Searching: mood")
const spotifyApiCall = await fetch(`https://api.spotify.com/v1/browse/categories/mood/playlists?`, {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${this.state.token}`,
"Content-Type":'application/json'
}
})
const spotify = await spotifyApiCall.json();
console.log("Items", spotify);
this.setState({
DATA: spotify.playlists.items,
})
}
catch (err)
{
console.log("Error fetching data", err);
}
}
fetchTracks = async (playlistId) => {
console.log('Playlist ', playlistId)
try
{
const getplaylist = await fetch(`https://api.spotify.com/v1.playlist/${playlistId}`,
{
method:'GET',
headers: {
Accept:"application/json",
Authorization:`Bearer ${this.state.token}`,
"Content-Type":"application/json"
}
});
const playlist = await getplaylist.json();
console.log('music ', playlist.tracks.items[0].preview_url);
}
catch (err)
{
console.log("Error fetching data ", err);
}
}
async _loadNewPlaybackInstance(playing, track) {
if(this.playbackInstance != null)
{
await this.playbackInstance.unloadAsync();
this.playbackInstance.setOnPlaybackStatusUpdate(null);
this.playbackInstance = null;
}
const source = {uri: track};
const initialStatus = {
shouldPlay: true,
rate: 1.0,
shouldCorrectPitch: true,
volume: 1.0,
isMuted: false
};
const {sound, status} = await Audio.Sound.createAsync(
source.initialStatus);
this.playbackInstance=sound;
this.playbackInstance.setIsLoopingAsync(false);
this.playbackInstance.playAsync();
if (this.state.selected === playlistId) {
console.log("Playing, so stop");
this.setState({selected:null});
this.playbackInstance.pauseAsync();
return;
}
this.setState({ selected:playlistId});
this._loadNewPlaybackInstance(true, playlist.tracks.items[0].preview_url);
}
render() {
if(!this.state.fontsLoaded ) {
return null
}
return (
<Container>
<Titlebar>
<Title>Music</Title>
</Titlebar>
<HeaderBar2>
<TouchableHighlight onPress={() => this.search()}>
<Header2>Playlists for your Mood</Header2>
</TouchableHighlight>
</HeaderBar2>
<View style={styles.MainContainer}>
{
this.state.DATA.length == 0 &&
<Text style={{padding:10, color:'#D3D3D3'}}/>
}
<FlatList
data = {this.state.DATA}
renderItem={item}
keyExtractor = {item.id}
numColumns={2}
extraData = {this.state}
/>
</View>
</Container>
);
}
}
I think u just have a little typo ..
check this line: <Text>{item.name}</Text>/>
change the last Text to </Text>

Get save data in different page by async saveToStorage(userData)

I am creating a react native app and doing the login and profile page. I have used the "async saveToStorage(userData)" for save the user data. Now i want to get the same data in the profile page.
I want to use this
getData = async () => {
try {
const value = await AsyncStorage.getItem('#storage_Key')
if(value !== null) {
// value previously stored
}
} catch(e) {
// error reading value
}
}
But how to use this in my profile page to Show this.
I saved this in the login page
async saveToStorage(userData){
if (userData) {
await AsyncStorage.setItem('user', JSON.stringify({
isLoggedIn: true,
authToken: userData.auth_token,
id: userData.user_id,
name: userData.user_login
})
);
return true;
}
return false;
}
And in the Profile page i have to display the name only. So how can use that.
import AsyncStorage from '#react-native-community/async-storage';
export default class Profile extends Component {
constructor(props){
super(props)
this.state={
userEmail:'',
userPassword:'',
}
}
var uservalue = await AsyncStorage.getItem('user');
home() {
Actions.home()
}
render() {
return (
<View style={styles.container}>
<View style={styles.header}></View>
<Image style={styles.avatar} source={{uri: 'https://bootdey.com/img/Content/avatar/avatar6.png'}}/>
<View style={styles.body}>
<View style={styles.bodyContent}>
<Text style={styles.name}>Robert Vadra</Text>
<Text style={styles.info}>Total Token: 30 {uservalue.name}</Text>
<Text style={styles.description}>Lorem ipsum dolor sit amet, saepe sapientem eu nam. Qui ne assum electram expetendis, omittam deseruisse consequuntur ius an,</Text>
<TouchableOpacity style={styles.buttonContainer} onPress={this.home} >
<Text style={styles.buttonText}>Play Now</Text>
</TouchableOpacity>
</View>
</View>
</View>
);
}
}
In the place of "Robert Vadra", i want to display the stored value in it. Please help in this. Thanks in advance.
My Login page
export default class LoginForm extends Component<{}> {
constructor(props){
super(props)
this.state={
isLoggedIn:false,
userEmail:'',
userPassword:'',
}
}
login = () =>{
this.state.validating = true;
const {userEmail,userPassword} = this.state;
let reg = /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/ ;
if(userEmail==""){
this.setState({email:'Please enter Email address'})
}
else if(reg.test(userEmail) === false)
{
this.setState({email:'Email is Not Correct'})
return false;
}
else if(userPassword==""){
this.setState({email:'Please enter password'})
}
else{
fetch('http://mojse.com/wetest/userlogin.php',{
method:'post',
header:{
'Accept': 'application/json',
'Content-type': 'application/json'
},
body:JSON.stringify({
email: userEmail,
password: userPassword
})
})
.then((response) => response.json())
.then((responseJson)=>{
let data = responseJson.data;
if (this.saveToStorage(data)){
/* Redirect to home page */
Actions.profile()
} else {
alert("Wrong Login Details");
}
})
.catch((error)=>{
console.error(error);
});
}
Keyboard.dismiss();
}
render(){
return(
<View style={styles.container}>
<TextInput style={styles.inputBox}
underlineColorAndroid='rgba(0,0,0,0)'
placeholder="Email"
placeholderTextColor = "#ffffff"
selectionColor="#fff"
keyboardType="email-address"
onChangeText={userEmail => this.setState({userEmail})}
/>
<TextInput style={styles.inputBox}
underlineColorAndroid='rgba(0,0,0,0)'
placeholder="Password"
secureTextEntry={true}
placeholderTextColor = "#ffffff"
ref={(input) => this.password = input}
onChangeText={userPassword => this.setState({userPassword})}
/>
<TouchableOpacity style={styles.button} onPress={this.login} >
<Text style={styles.buttonText}>Login</Text>
</TouchableOpacity>
</View>
)
}
async saveToStorage(userData){
if (userData) {
await AsyncStorage.setItem('user', JSON.stringify({
isLoggedIn: true,
authToken: this.state.authToken,
id: this.state.userid,
name: "KKKKKK"
})
);
return true;
}
return false;
}
}
You can get user data in the componentDidMount and save it to a state like this:
constructor(props){
super(props)
this.state={
userEmail:'',
userPassword:'',
userName:'',
}
}
componentDidMount() {
AsyncStorage.getItem('user').then((uservalue)=>{
uservalue = JSON.Parse(uservalue)
this.setState({userName: uservalue.name})
})
}
Now, you can use userName like this:
<Text style={styles.name}>{this.state.userName}</Text>
EDIT
First, please check that server response is correct ( maybe console.log(data) before save). Second, you are calling an async function so you have to wait until save function finish its work. also in save function, double check your data. my suggestion:
fetch('http://mojse.com/wetest/userlogin.php',{
method:'post',
header:{
'Accept': 'application/json',
'Content-type': 'application/json'
},
body:JSON.stringify({
email: userEmail,
password: userPassword
})
})
.then((response) => response.json())
.then(async (responseJson) => { // this is an async function
let data = responseJson.data;
console.log(data) // check and validate data correction
let res = await this.saveToStorage(data)
if (res){
/* Redirect to home page */
Actions.profile()
} else {
alert("Wrong Login Details");
}
})
.catch((error)=>{
console.error(error);
});
saveToStorage = async (userData) => {
if (userData) {
let model = { // full model with received data. this.state. authToken is not valid because we do not have a state called authToken.
isLoggedIn: true,
authToken: userData.authToken,
id: userData.userid,
name: userData.name
}
await AsyncStorage.setItem('user', JSON.stringify(model))
return true;
}
return false;
}
this is what i thik may be wrong and i did not test it. double check your code please.
I hope this can help you.

React Native Flat List doesn't call onEndReached handler after two successful calls

I implement a very simple list that calls a server that returns a page containing books.Each book has a title, author, id, numberOfPages, and price). I use a Flat List in order to have infinite scrolling and it does its job very well two times in a row (it loads the first three pages) but later it doesn't trigger the handler anymore.
Initially it worked very well by fetching all available pages, but it stopped working properly after I added that extra check in local storage. If a page is available in local storage and it has been there no longer than 5 seconds I don't fetch the data from the server, instead I use the page that is cached. Of course, if there is no available page or it is too old I fetch it from the server and after I save it in local storage.(Something went wrong after adding this behavior related to local storage.)
Here is my component:
export class BooksList extends Component {
constructor(props) {
super(props);
this.state = {
pageNumber: 0
};
}
async storePage(page, currentTime) {
try {
page.currentTime = currentTime;
await AsyncStorage.setItem(`page${page.page}`, JSON.stringify(page));
} catch (error) {
console.log(error);
}
}
subscribeToStore = () => {
const { store } = this.props;
this.unsubsribe = store.subscribe(() => {
try {
const { isLoading, page, issue } = store.getState().books;
if (!issue && !isLoading && page) {
this.setState({
isLoading,
books: (this.state.books ?
this.state.books.concat(page.content) :
page.content),
issue
}, () => this.storePage(page, new Date()));
}
} catch (error) {
console.log(error);
}
});
}
componentDidMount() {
this.subscribeToStore();
// this.getBooks();
this.loadNextPage();
}
componentWillUnmount() {
this.unsubsribe();
}
loadNextPage = () => {
this.setState({ pageNumber: this.state.pageNumber + 1 },
async () => {
let localPage = await AsyncStorage.getItem(`page${this.state.pageNumber}`);
let pageParsed = JSON.parse(localPage);
if (localPage && (new Date().getTime() - localPage.currentTime) < 5000) {
this.setState({
books: (
this.state.books ?
this.state.books.concat(pageParsed.content) :
page.content),
isLoading: false,
issue: null
});
} else {
const { token, store } = this.props;
store.dispatch(fetchBooks(token, this.state.pageNumber));
}
});
}
render() {
const { isLoading, issue, books } = this.state;
return (
<View style={{ flex: 1 }}>
<ActivityIndicator animating={isLoading} size='large' />
{issue && <Text>issue</Text>}
{books && <FlatList
data={books}
keyExtractor={book => book.id.toString()}
renderItem={this.renderItem}
renderItem={({ item }) => (
<BookView key={item.id} title={item.title} author={item.author}
pagesNumber={item.pagesNumber} />
)}
onEndReachedThreshold={0}
onEndReached={this.loadNextPage}
/>}
</View>
)
}
}
In the beginning the pageNumber available in the state of the component is 0, so the first time when I load the first page from the server it will be incremented before the rest call.
And here is the action fetchBooks(token, pageNumber):
export const fetchBooks = (token, pageNumber) => dispatch => {
dispatch({ type: LOAD_STARTED });
fetch(`${httpApiUrl}/books?pageNumber=${pageNumber}`, {
headers: {
'Authorization': token
}
})
.then(page => page.json())
.then(pageJson => dispatch({ type: LOAD_SUCCEDED, payload: pageJson }))
.catch(issue => dispatch({ type: LOAD_FAILED, issue }));
}
Thank you!