Use a variable inside a render of react native - javascript

I need to use the url from a json and render it on the screen, using React Native and axios.
I'm getting the url with this:
teste() {
api.get('photos').then(
function imagens(response) {
var i = 1;
for (i; i < 2; i++) {
urlDaImagem = response.data[i].url
console.log('em cima->' + urlDaImagem)
}
return urlDaImagem
})
}
I need to put that "urlDaImagem" inside of a Image component.
The entire code:
import React from 'react';
import {
SafeAreaView,
StyleSheet,
ScrollView,
View,
Image,
StatusBar
} from 'react-native';
import api from '../api';
var urlDaImagem
class PaginaPrincipal extends React.Component {
teste() {
api.get('photos').then(
function imagens(response) {
var i = 1;
for (i; i < 2; i++) {
urlDaImagem = response.data[i].url
console.log('em cima->' + urlDaImagem)
}
return urlDaImagem
})
}
render() {
return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView>
<ScrollView contentInsetAdjustmentBehavior="automatic">
<View style={styles.sideBySideImages}>
<Image style={styles.imagens} source={{ uri: urlDaImagem }} />
</View>
</ScrollView>
</SafeAreaView>
</>
)
}
}
const styles = StyleSheet.create({
imagens: {
width: "45%",
height: 183,
marginBottom: 5,
marginTop: 5,
marginStart: "3%",
marginEnd: "1%"
},
sideBySideImages: {
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap'
}
});
export default PaginaPrincipal;

To load data from API it is better to use useEffect hook (React native supports it):
https://reactjs.org/docs/hooks-effect.html#explanation-why-effects-run-on-each-update
Also, React to work properly should control the state of your components. You have to declare state by useState hook, for example. Global vars won't work without tricks)
function PaginaPrincipal(props) {
const [urlDaImagem, setUrlDaImagem] = useState();
useEffect(
() => {
api.get('photos').then(({ data }) => {
console.log(data);
const [{ url }] = data;
setUrlDaImagem(url);
});
},
[] // Effect does not depend on any props
);
return (
<>
...
<Image style={styles.imagens} source={{ uri: urlDaImagem }} />
...
</>
);
}

you can use state in your case, read about it from here: https://reactjs.org/docs/state-and-lifecycle.html
and I updated your code try to test it, and see the best life cycle to call teste function and this should do the trick
import React from 'react';
import {
SafeAreaView,
StyleSheet,
ScrollView,
View,
Image,
StatusBar
} from 'react-native';
import api from '../api';
class PaginaPrincipal extends React.Component {
state={
urlDaImagem:""
}
teste() {
api.get('photos').then(
function imagens(response) {
var i = 1;
let urlDaImagem;
for (i; i < 2; i++) {
urlDaImagem = response.data[i].url
console.log('em cima->' + urlDaImagem)
}
this.setState({urlDaImagem})
})
}
render() {
return (
<>
<StatusBar barStyle="dark-content" />
{ this.state.urlDaImagem &&
<SafeAreaView>
<ScrollView contentInsetAdjustmentBehavior="automatic">
<View style={styles.sideBySideImages}>
<Image style={styles.imagens} source={{ uri: this.state.urlDaImagem }} />
</View>
</ScrollView>
</SafeAreaView>
}
</>
)
}
}
const styles = StyleSheet.create({
imagens: {
width: "45%",
height: 183,
marginBottom: 5,
marginTop: 5,
marginStart: "3%",
marginEnd: "1%"
},
sideBySideImages: {
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap'
}
});
export default PaginaPrincipal;

Related

React Native and map

I have an issue in my project. I want to show elements after I get them from the JSON. When I am trying to observe content of JSON I see it, but when I am trying to show it in my component it doesn't appear. Also debugger don't show any errors or problrms and app compiles sucessfully. I am really stuck, so I really need your help guys
App.js code:
import React, { Component } from 'react'
import { View, ScrollView, StyleSheet } from 'react-native'
import { Header, ImageCard } from './src/components/uikit'
const url = 'https://s3.eu-central-1.wasabisys.com/ghashtag/RNForKids/00-Init/data.json'
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
title: 'STAR GATE',
data: []
};
}
componentDidMount = async () => {
try {
const response = await fetch(url)
const data = await response.json()
this.setState({ data })
}
catch (e) {
console.log(e)
throw e
}
}
render() {
const { title, data } = this.state
const { container } = style
return (
<View>
<Header title={title} />
<ScrollView>
<View style={container}>
{data.map(item => {
<ImageCard data={item} key={item.id} />
})
}
</View>
</ScrollView>
</View>
)
}
}
const style = StyleSheet.create({
container: {
marginTop: 30,
flexDirection: 'row',
flexWrap: 'wrap',
flexShrink: 2,
justifyContent: 'space-around',
marginBottom: 150,
backgroundColor: 'gold',
width: 150
}
})
My problem happens in App.js inside the
And ImageCard code:
import React from 'react'
import { Image, View, Text, StyleSheet } from 'react-native'
import { h, w } from '../../../constants'
const ImageCard = ({data}) => {
const {container, sub, h2, cover} = styles
const {image, name} = data
return (
<View style={container}>
<View style={sub}>
<Image
style={cover}
source={{
uri: image,
}}
/>
</View>
<Text style={h2}>{name.toUpperCase()}</Text>
</View>
)
}
const styles = StyleSheet.create({
container: {
width: w / 2.1,
paddingVertical: 10,
},
sub: {
padding:10,
shadowColor: 'black',
shadowRadius: 8,
shadowOffset: { width: 0, height: 5 },
shadowOpacity: 0.4,
},
h2: {
fontFamily: 'AvenirNext-DemiBold',
fontSize: 16,
alignSelf: 'center',
textAlign: 'center',
width: w / 2.4
},
cover: {
width: w / 2.4,
height: w * 0.63,
borderRadius: 10
}
})
export { ImageCard }
It should be ok, I made it by guide, but something went wrong.
It looks like you're not returning anything from map!
data.map(item => {
<ImageCard data={item} key={item.id} />
})
should become
data.map(item => {
return <ImageCard data={item} key={item.id} />
})
// OR
data.map(item => ( // <-- Note the bracket change
<ImageCard data={item} key={item.id} />
))

My simple react native project won't render, any suggestions?

I'm using the expo application on my phone to build a simple react native application, but I'm unable to render simple text. Is there something I'm doing wrong?
import React, { Component } from 'react';
import { StyleSheet, Text, View, Image } from 'react-native';
import bball from './assets/bball.jpeg'
export default class App extends Component {
render() {
let pic = {
uri: bball
}
return (
<View style={styles.container}>
<Text>hello, world</Text>
<Image source={{pic}} />
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Have you tried this way?
import React, { Component } from 'react';
import { StyleSheet, Text, View, Image } from 'react-native';
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<Text>hello, world</Text>
<Image source={require('./assets/bball.jpeg')} />
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
#Myers Nii-Ansah, try to import image like
const image = require('./my-icon.png');
just use directly bbal in the source of image.
<Image source={bbal} />
if you have url of any image use like this.
<Image source={{uri: "https://example.com/image.png"}} />
so you can do this way if any how you can have image url from your component state.
render() {
let pic = this.state.url ? { uri: this.state.url } : bbal
return (
<View style={styles.container}>
<Text>hello, world</Text>
<Image source={pic} />
</View>
)
}

Invariant Violation: Element type is invalid:expected a string(for built-in components) or a class/function(for composite component)but got: undefined

I am using following version to build a app
React-Native:0.57.1
react-native-cli:2.0.1
node:v8.11.3
npm:5.6.0
It says that check render method of List. So i am sharing the code of List.js below.
List.js
import React, {Component} from 'react';
import {
Text,
TextInput,
Dimensions,
ImageBackground,
Alert,
TouchableHighlight,
StyleSheet,
NativeModules,
PixelRatio,
ToastAndroid,
View,
ListView,
RefreshControl,
BackHandler
} from 'react-native';
import RNExitApp from 'react-native-exit-app';
import Icon from 'react-native-vector-icons/MaterialIcons';
import Icon1 from 'react-native-vector-icons/Foundation';
import IconHeart from 'react-native-vector-icons/FontAwesome';
import Realm from 'realm';
import { Toolbar, ThemeProvider} from 'react-native-material-ui';
import { NavigationActions,Header,StackNavigator } from 'react-navigation';
import Auth from './lib/Categories/Auth';
import AndroidBackButton from './back-button';
import LocalStorage from './lib/Categories/LocalStorage';
import {MetaData,SchemaData,HistoryTable} from './Schema';
import { sync } from './Components/Sync'
import strings from './Language';
import Storage from './lib/Categories/Storage';
import costyle from './Styling';
import { GoogleAnalyticsTracker } from "react-native-google-analytics-bridge";
let tracker = new GoogleAnalyticsTracker(strings.analytics);
var RNFS=require('react-native-fs');
const SCREEN_WIDTH = Dimensions.get('window').width;
const SCREEN_HEIGHT = Dimensions.get('window').height;
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
const uiTheme = {
palette: {
primaryColor: '#008975',
},
toolbar:{
container:{height:SCREEN_HEIGHT*0.08}
},
};
export default class List extends Component
{
constructor(props) {
super(props);
this.state = {
dataSource: ds.cloneWithRows([]),
realm:null,
refresh:false,
timePassed:false,
c:0,
data:[],
}
}
componentWillMount(){
Realm.open({
schema:[SchemaData,MetaData]
}).then(realm => {
this.setState({realm});
})
.done(()=>this.loadJSONData())
tracker.trackEvent("Home Screen", "opened");
}
componentWillUnmount(){
tracker.trackEvent("Home Screen","closed");
}
setSearchText(searchText){
var arr=this.state.data;
let results = [];
for(var i = 0; i < arr.length; i++)
{
if(arr[i].property1.toLowerCase().includes(searchText.toLowerCase()))
results.push(arr[i]);
else if(arr[i].doctor.toLowerCase().includes(searchText.toLowerCase()))
results.push(arr[i]);
}
this.setState({
searchText,
dataSource: this.state.dataSource.cloneWithRows(results),
});
}
backOfList(){
setTimeout(() => {this.setState({timePassed:true,c:0})}, 5000);
var c=this.state.c;
if (!this.state.timePassed)
{
this.setState({c:c+1});
if(this.state.c==1)
ToastAndroid.show(strings.pressExit, ToastAndroid.SHORT);
else if(this.state.c==2){
RNExitApp.exitApp();
}
}
else
{
this.setState({c:1});
ToastAndroid.show(strings.pressExit, ToastAndroid.SHORT);
this.setState({timePassed:false});
}
console.log(c);
}
async sync() {
this.setState({ refresh: true });
setTimeout(() => {this.setState({ refresh: false });}, 10000);
try{
await sync()
}catch(e){
if(e.name=='TypeError'){
await Auth.init();
}
else
ToastAndroid.show(strings.wrongWarning, ToastAndroid.SHORT);
}
this.loadJSONData()
}
loadJSONData()
{
var arr=[];
this.setState({dataSource: this.state.dataSource.cloneWithRows(arr)})
console.log("inside loadJSONData")
arr=this.state.realm.objects('SchemaData').sorted('modifiedTime',true);
arr=arr.filtered('userId==$0 AND active==$1',LocalStorage.getItem('UserId'),true);
this.setState({ refresh: false });
this.setState({ data:arr,dataSource: this.state.dataSource.cloneWithRows(arr)})
}
renderedRow(data){
const { navigate } = this.props.navigation;
var files=[],file=[];
var pCount;
var lCount;
var oCount;
console.log('Render row:',data)
if(this.state.realm!=null)
{
file=this.state.realm.objects('MetaData');
files=file.filtered('ailmentId == $0 AND category == "Prescription" AND active == $1',data.id,true)
pCount=files.length;
files=file.filtered('ailmentId == $0 AND category == "LabWork" AND active == $1',data.id,true)
lCount=files.length;
files=file.filtered('ailmentId == $0 AND category == "Others" AND active == $1',data.id,true)
oCount=files.length;
}
return(
<View>
<View style={{flex:1,marginTop:10,flexDirection:'row'}}>
<View style={{flex:10}}>
<TouchableHighlight underlayColor='transparent' onPress={()=>{navigate('imageGrid',{loadData:this.loadJSONData.bind(this),type:'Details',data:data})}}>
<View>
<Text style={{marginLeft:15,fontSize:20,fontWeight:'bold'}}>
{data.property1}
</Text>
<Text style={{marginLeft:15,fontSize:15}}>{strings.prescription}: <Text style={{fontWeight:'bold'}}>{pCount}</Text> <Text style={{color:'#babcbc'}}>|</Text>{strings.labworkHeading2}: <Text style={{fontWeight:'bold'}}>{lCount}</Text> <Text style={{color:'#babcbc'}}>|</Text> {strings.others}: <Text style={{fontWeight:'bold'}}>{oCount}</Text></Text>
</View>
</TouchableHighlight>
</View>
<View style={styles.icons}>
<Icon1 name='page-add' size={SCREEN_WIDTH*0.1} onPress={()=>{navigate('PickCategory',{data:data})}}/>
</View>
</View>
<View style={[costyle.line,{marginLeft:10}]}/>
</View>
);
}
render(){
const { navigate } = this.props.navigation;
return (
<View style={costyle.bagContainer}>
<AndroidBackButton onPress={()=>{this.backOfList();return true}} />
<ThemeProvider uiTheme={uiTheme}>
<Toolbar
leftElement="menu"
size={SCREEN_WIDTH * 0.0675}
centerElement={strings.AddDetails}
searchable={{
autoFocus: true,
placeholder: strings.placeholderSearch,
onChangeText:this.setSearchText.bind(this)
}}
style={{
titleText:{fontFamily:'sans-serif',fontSize:20,fontWeight:'normal'}
}}
onLeftElementPress= {()=> navigate('DrawerOpen')}
/>
</ThemeProvider>
<ImageBackground
source={require('./Images/BackgroundImage.png')}
style={{ width: SCREEN_WIDTH,height: SCREEN_WIDTH * 0.1}}>
<Text style={{marginTop:5,color:'#005b4a',fontSize:22,marginLeft:20,fontWeight:'bold'}}>{strings.wellnessrecord}</Text>
</ImageBackground>
<Text></Text>
<ListView enableEmptySections
dataSource={this.state.dataSource}
renderRow={this.renderedRow.bind(this)}
refreshControl={ <RefreshControl refreshing={this.state.refresh} onRefresh={this.sync.bind(this)} /> }/>
<View>
<TouchableHighlight style={styles.addButton}
underlayColor='#4b9e77' onPress={()=>{navigate('AddDetails',{goback:'true'})}}>
<Icon name='add' size={32} color='white'/>
</TouchableHighlight>
</View>
</View>
);
}
static navigationOptions= ({ navigation }) => ({
header:null,
});
}
const styles = StyleSheet.create({
icons: {
flex:1,
alignItems:'flex-end',
justifyContent:'center',
paddingRight:20,
paddingBottom:10,
},
addButton: {
backgroundColor: '#005b4a',
height: 60,
width: 60,
borderRadius: 30,
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
bottom: 20,
right:20,
}
});
I am getting this error and unable to resolve it, although this error has been discussed in stackoverflow but i have tried those code but still it didn't worked. Kindly help.

How to render a loader until data is fetched in React Native

I am fetching data through an async request. I know that I need to wait for the api request to complete before displaying the data. Unfortunately, I'm not sure how to create a loader to wait for the data to load.I am new to react, so if I could also get help with implementing it as well, that would be fantastic! Here is my current code:
import React, { Component, PropTypes } from 'react';
import { View, Text, ListView, StyleSheet, TouchableHighlight} from 'react- native';
import Header from '../Components/Header';
import Api from '../Utility/Api';
export default class CalendarPage extends Component {
constructor(props) {
super(props);
}
async componentWillMount() { this.setState(
{data: await Api.getDates()},
)
}
render() {
return (
<View style={{flex: 1}}>
<Header pageName="Calendar" navigator={this.props.navigator}/>
<View style = {{flex:9}}>
<View>
{ this.state.data.days[0].items.map((item) => (
<View>
<Text>{item.summary}</Text>
<Text>{item.start.dateTime}</Text>
<Text>{item.description}</Text>
</View>
))}
</View>
</View>
</View>
);
}
}
A simple example using ActivityIndicator -
import ActivityIndicator
import { View, Text, ListView, StyleSheet, TouchableHighlight, ActivityIndicator} from 'react- native';
set data state to null
constructor(props) {
super(props);
this.state = {
data: null
}
}
do conditional rendering
render() {
if (!this.state.data) {
return (
<ActivityIndicator
animating={true}
style={styles.indicator}
size="large"
/>
);
}
return (
<View style={{flex: 1}}>
<Header pageName="Calendar" navigator={this.props.navigator}/>
....
....
</View>
);
}
}
indicator style
const styles = StyleSheet.create({
indicator: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
height: 80
}
});
Although solution proposed by #vinayr works fine but user will still be able to click on screen and perform some action even while loader is being shown which can lead to crash.
One solution is wrap loader inside a Modal.
import React, { Component } from 'react';
import {
StyleSheet,
View,
Modal,
ActivityIndicator,
} from 'react-native';
const styles = StyleSheet.create({
modalBackground: {
flex: 1,
alignItems: 'center',
flexDirection: 'column',
justifyContent: 'space-around',
backgroundColor: '#00000040',
},
activityIndicatorHolder: {
backgroundColor: '#FFFFFF',
height: 100,
width: 100,
borderRadius: 10,
display: 'flex',
alignItems: 'center',
justifyContent: 'space-around',
},
});
const SmartLoader = (props) => {
const {
isLoading,
...attributes
} = props;
return (
<Modal
transparent
animationType={'none'}
visible={isLoading}
onRequestClose={() => { console.log('Noop'); }}
>
<View style={styles.modalBackground}>
<View style={styles.activityIndicatorHolder}>
<ActivityIndicator
animating={isLoading}
size="large"
/>
</View>
</View>
</Modal>
);
};
export default SmartLoader;
After that you can use it anywhere in your component, user will not be able to perform any action till loader is finished ( made hidden based on flag)

How to navigate page with React Native

I have a component for listing items, I want to add the function that can go to a different page, and that page has the detail about that item. Currently, this is my code for listing items.
import React, { Component } from 'react';
import { ScrollView } from 'react-native';
import axios from 'axios';
import CarDetail from './CarDetail';
const API_URL = 'http://localhost:3000';
class CarList extends Component {
state = { cars: [] };
componentWillMount() {
console.log('Mount');
axios.get(`${API_URL}/cars`)
.then(response => this.setState({ cars: response.data.cars }));
}
renderCars() {
return this.state.cars.map(car => <CarDetail key={car.id} car={car} />
);
}
render() {
console.log(this.state.cars);
return (
<ScrollView>
{this.renderCars()}
</ScrollView>
);
}
}
export default CarList;
and this is the code for describing items
import React from 'react';
import { Text, View, Image } from 'react-native';
import { Actions } from 'react-native-router-flux';
import Card from '../material/Card';
import CardSection from '../material/CardSection';
const CarDetail = ({ car }) => {
const imageURI = 'https://yt3.ggpht.com/-HwO-2lhD4Co/AAAAAAAAAAI/AAAAAAAAAAA/p9WjzQD2-hU/s900-c-k-no-mo-rj-c0xffffff/photo.jpg';
const { make, model } = car;
function showCarDetail() {
Actions.showCar();
}
return (
<Card>
<CardSection>
<View style={styles.containerStyle}>
<Image
style={styles.imageStyle}
source={{ uri: imageURI }}
/>
</View>
<View style={styles.headContentStyle}>
<Text
style={styles.headerTextStyle}
onPress={showCarDetail()}
>
{make}
</Text>
<Text>{model}</Text>
</View>
</CardSection>
<CardSection>
<Image
style={styles.picStyle}
source={require('./car.jpg')}
/>
</CardSection>
</Card>
);
};
const styles = {
headContentStyle: {
flexDirection: 'column',
justifyContent: 'space-around'
},
headerTextStyle: {
fontSize: 18
},
imageStyle: {
height: 50,
width: 50
},
containerStyle: {
justifyContent: 'center',
alignItems: 'center',
marginLeft: 10,
marginRight: 10
},
picStyle: {
height: 300,
flex: 1,
width: null
}
};
export default CarDetail;
How can I change my code for that? Can anyone give me an example?
You have to use some sort of navigation component. There are many out there, but personally I use the one that is built into React Native. https://facebook.github.io/react-native/docs/navigator.html

Categories

Resources