React Native Loading image off API Fetch data - react-native

I am new to React Native! And having problems with properly loading the image off the JSON that I get from JsonPlaceHolder API. I set the state of the photos and the titles. The titles were able to load, however, photos were not be able to load properly. I did search and there are suggestions to replace http to https call would fix it. But No luck here. Please help! And Thank in Advance!
import React, { Component } from 'react';
import {
Image,
StyleSheet,
Text,
View,
} from 'react-native';
export default class App extends Component {
constructor(props){
super(props);
this.state = {
photos: '',
titles: ''
};
}
componentWillMount(){
this.fetchData();
}
fetchData = async () => {
let response = await fetch('http://jsonplaceholder.typicode.com/photos/1');
let json = await response.json();
this.setState({titles: json.title, photos: json.url.replace('http','https')});
};
render() {
console.log(this.state.photos)
return (
<View style={styles.container}>
<Image
source={{uri: this.state.photos}}
style={{height: 600, width: 600}}
resizeMode= 'cover'
/>
<Text>
Title: {this.state.titles}
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#ecf0f1',
}
});

Hey so I ran your exact code except i replaced
this.setState({titles: json.title, photos: json.url.replace('http','https')});
with
this.setState( {
title: json.title,
photos: json.url,
} )
and it works fine for me, it simply gives me the error for not having an empty string as uri which is expected.

Related

How to show loading progress or spinner in the middle of the screen with React Native?

I am developing React Native app.
I was able to solve all problems by myself but this is exception.
I am going to load another screen with bottom tab navigator.
For example, after user login to the app, it should show main home screen which has many pictures and many style sheet effects, icons. Because of that, after login confirm ( I mean after alert of the login confirm), the main home screen appears after a few seconds.
So I want to show some spinner in the login screen while loading main home screen in the background and when it is ready to show, erase spinner and show main home screen.
How can I do this?
My bottom tab navigator was simply created with createBottomTabNavigator() method.
So in your case you can do several things
You can use React Native Activity Indicator -> View
You can use Overlay Library -> react-native-loading-spinner-overlay -> View GitHub
If you like to make loading like facebook / instagram -> then use react-native-easy-content-loader -> View GitHub
Assume that you are using React Native Activity Indicator :
import { ActivityIndicator } from "react-native";
export default class HomeScreen extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true
};
}
//Get Home Screen Data API Action
componentDidMount() {
this.loadAPI(); // Call home screen get data API function
}
//Login API Function
loadAPI = () => {
this.setState({ isLoading: true }); // Once You Call the API Action loading will be true
fetch(API_URL, {
method: "POST",
headers: {
"Content-Type": "application/json"
}
})
.then(response => response.json())
.then(responseText => {
// You can do anything accroding to your API response
this.setState({ isLoading: false }); // After getting response make loading to false
})
.catch(error => {});
};
render() {
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
{this.state.isLoading && <ActivityIndicator color={"#fff"} />}
</View>
);
}
}
If you want to hide all the view until loading finish like images, so you can use custom library instead of Activity Indicator.
I have created my custom Loader component. Using this you can display built in ActivityIndicator or your custom gif loader image with overlay.
Loader.js
import React, { Component } from 'react';
import {
StyleSheet,
View,
Modal,
Image,
ActivityIndicator
} from 'react-native';
class Loader extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: this.props.isLoading
}
}
static getDerivedStateFromProps(nextProps) {
return {
isLoading: nextProps.isLoading
};
}
render() {
return (
<Modal
transparent={true}
animationType={'none'}
visible={this.state.isLoading}
style={{ zIndex: 1100 }}
onRequestClose={() => { }}>
<View style={styles.modalBackground}>
<View style={styles.activityIndicatorWrapper}>
<ActivityIndicator animating={this.state.isLoading} color="black" />
{/* If you want to image set source here */}
{/* <Image
source={require('../assets/images/loader.gif')}
style={{ height: 80, width: 80 }}
resizeMode="contain"
resizeMethod="resize"
/> */}
</View>
</View>
</Modal>
)
}
}
const styles = StyleSheet.create({
modalBackground: {
flex: 1,
alignItems: 'center',
flexDirection: 'column',
justifyContent: 'space-around',
backgroundColor: '#rgba(0, 0, 0, 0.5)',
zIndex: 1000
},
activityIndicatorWrapper: {
backgroundColor: '#FFFFFF',
height: 100,
width: 100,
borderRadius: 10,
display: 'flex',
alignItems: 'center',
justifyContent: 'space-around'
}
});
export default Loader
Now you can use it when you have to display loading indicator as below :
<Loader isLoading={this.state.isLoading} />
import { ActivityIndicator } from 'react-native';
export default class LoginScreen extends Component {
constructor(props) {
super(props);
this.state = {
spinner : true
}
}
render() {
return (
<View style={{flex : 1, justifyContent: 'center', alignItems: 'center',}}>
{
this.state.spinner &&
<ActivityIndicator color={'#fff'} />
}
</View>
)
}
}
So you can show the SPinner for suppose when you have to load an API or something and when you get the response of api, you can set spinner loading value to false.
For eg :
import {View, ActivityIndicator } from 'react-native';
export default class MainScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
spinner : true
}
}
componentDidMount(){
this.loadApi();
}
loadApi = async() => {
let result = axios.get('url').then((data) =>{
this.setState({spinner:false});
}
).catch((err) => this.setState({spinner:false})
}
render() {
return (
<View style={{flex : 1, justifyContent: 'center', alignItems: 'center',}}>
{
this.state.spinner? <ActivityIndicator color={'#fff'} />:<View><Text>Data loaded</Text></View>
}
</View>
)
}
}
you have to use ActivityIndicator you can have to load this activityindicator before getting data from the server , you have to check below code hope you will understand
import React, {useEffect, useState} from 'react';
import {ActivityIndicator, View, Dimensions} from 'react-native';
import HomeScreen from './Home';
const DataViewer = () => {
const [data, setData] = useState([]);
const {height, width} = Dimensions.get('window');
useEffect(() => {
fetch('http://example.com/movies.json')
.then(response => {
return response.json();
})
.then(myJson => {
setData(myJson);
});
});
return data.length > 0 ? (
<HomeScreen data={data} />
) : (
<View
style={{justifyContent: 'center', alignItems: 'center', height, width}}>
<ActivityIndicator size="large" color="#0000ff" />
</View>
);
};
export default DataViewer;
You can use the Activity indicator as the default loading animation. But you can also use Lottie files to implement custom loading screen animation on your project by installing npm i lottie-react-native or yarn add lottie-react-native

How Can I Display SVG Data In React Native?

I have some SVG image data that I would like to import into my React Native App.
Is there any way to take my raw SVG image data and display it without saving it to a file?
I have an api that will create an image based from any given text (coolProgrammer123) and will return the SVG image data.
https://api.kwelo.com/v1/media/identicon/coolProgrammer123?format=base64
Any Ideas? Thanks.
I'll suggest you try out react-native-svg-uri
import SvgUri from 'react-native-svg-uri';
const TestSvgUri = () => (
<View style={styles.container}>
<SvgUri
width="200"
height="200"
source={{uri:'http://thenewcode.com/assets/images/thumbnails/homer-simpson.svg'}}
/>
</View>
);
UPDATE
Here is a code snippet on how you can use to use axios to get the SVG from the URL and pass it to the Image tag without using the above npm package.
import React, { Component } from 'react';
import { View, Image } from 'react-native';
import axios from 'axios';
class App extends Component {
constructor(props) {
super(props);
this.state = {
imageUri: ''
}
}
componentDidMount() {
this.getSvg();
}
getSvg = () => {
let image_base64;
axios.get('https://api.kwelo.com/v1/media/identicon/coolProgrammer123?format=base64')
.then(response => {
image_base64 = response.data;
this.setState({
...this.state,
imageUri: image_base64
})
})
.catch(function (error) {
console.log(error);
});
return image_base64;
}
render(){
return (
<View>
<Image
style={{
width: 81,
height: 81,
resizeMode: 'contain',
marginTop: 180,
marginLeft: 20,
marginRight: 20,
alignSelf: "center"
}}
source={{ uri: this.state.imageUri }}
/>
</View>
);
}
};
export default App;

React native snapshot screen

I am building an app for iOS with React native and I would like to know how to take a snapshot of a given screen. I have found this library but I don't know how to use it. Does anyone know how to ?
EDIT:
I used the following code to capture a screen using the library but I get the given error.
try {
captureRef(viewRef, {
format: "jpg",
quality: 0.8
})
.then(
uri => console.log("Image saved to", uri),
error => console.error("Oops, snapshot failed", error)
);
} catch (e) {
console.log(e);
}
The error
ReferenceError: viewRef is not defined
Does anybody know how to fix the error?
Thank you
Sure, but you have to read a little about what a ref is. If you are already using React hooks, check this: https://es.reactjs.org/docs/hooks-reference.html#useref
(if not, just search on how to create a ref in React with createRef)
Basically, a ref is something that will let you identify your component using the same variable even if the component re-renders. So, viewRef in your example should be a reference to a given element. Like:
import React, { useRef } from "react";
function MyComponent() {
const viewRef = useRef();
return <View ref={viewRef}>content</View>
}
So, your draft could be something like:
import React, { useRef } from "react";
import {Button, View, Text} from 'react-native';
import { captureRef } from "react-native-view-shot";
function useCapture() {
const captureViewRef = useRef();
function onCapture() {
captureRef(captureViewRef, {
format: "jpg",
quality: 0.9
}).then(
uri => alert(uri),
error => alert("Oops, snapshot failed", error));
}
return {
captureViewRef,
onCapture
};
}
function MyComponent() {
const { captureViewRef, onCapture } = useCapture();
return (
<>
<View ref={captureViewRef}><Text>content</Text></View>
<Button title="Save" onPress={onCapture} />
</>
);
}
As far as I know, this only generates a temporary file. If you want to see the capture saved into your device, you should use CameraRoll https://facebook.github.io/react-native/docs/cameraroll
I won't cover how to use it here, but it would be something like:
CameraRoll.saveToCameraRoll(uri); // uri being the path that you get from captureRef method
Just notice that your app must ask for proper permission before attempting to save to the device gallery.
hi this can be with the help of react-native-view-shot
this is my parent component
import React, {Component,useRef} from 'react';
import {Platform, StyleSheet, Text, View,Image,Button} from 'react-native';
import { captureRef, captureScreen ,ViewShot} from "react-native-view-shot";
import NewVd from './NewVd';
import Newved from './Newved';
export default class App extends Component {
constructor(){
super();
this.state={
item:null,
captureProcessisReady:false,
myView:false
};
this.func=this.func.bind(this);
}
componentDidMount(){
}
result1=()=>{
console.log("i am here ");
this.setState({captureProcessisReady:true});
}
func = (uri) => {
console.log('ADD item quantity with id: ', uri);
this.setState({item:uri,myView:true});
};
render() {
return (
<View style={styles.container}>
{/* <NewVd
func={this.func}/> */}
<Newved />
<Text>...Something to rasterize...</Text>
<Text style={styles.welcome}>Welcome to React Native!</Text>
<Text style={styles.instructions}>To get started, edit App.js</Text>
<Button onPress={()=>this.result1()} title="press Me"/>
<View>
{this.state.captureProcessisReady?( <NewVd func={this.func}/>):null}
</View>
<View>
{this.state.myView?( <Image source={{uri:this.state.item !== null?`${this.state.item}`:'https://picsum.photos/200'}} style={{width:100,height:100}} />):null}
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
this is my child component
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View} from 'react-native';
import ViewShot from "react-native-view-shot";
class NewVd extends Component {
constructor(props){
super(props);
}
onCapture = uri => {
console.log("do something with ", uri);
this.props.func(uri); //for the parent using callback
}
render() {
return (
<ViewShot onCapture={this.onCapture} captureMode="mount">
<Text>...Something to rasterize...</Text>
</ViewShot>
);
}
}
export default NewVd;

React Native code explanation

I have a simple app application project that I would appreciate if someone would explain the logic behind the code.
On the click on the button the text that is inside the text input appears on the imageBackground.
FilterView.js:
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
Image,
Button, Platform, TouchableOpacity, TextInput, ImageBackground } from 'react-native';
import { captureRef } from "react-native-view-shot";
import { Input } from 'react-native-elements';
import DynamicText from './DynamicText';
export default class FilterView extends Component {
constructor(props) {
super(props);
this.state = {
text: '',
imageURI: 'https://reactnativecode.com/wp-content/uploads/2018/02/motorcycle.jpg',
}
}
captureScreenFunction = () => {
captureRef({
format: "jpg",
quality: 0.8
})
.then(
uri => this.setState({ imageURI: uri }),
error => console.error("Oops, Something Went Wrong", error)
);
}
onTextReceived = (text) => {
this.setState({text});
}
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Button title="Capture Device Screenshot" onPress={this.captureScreenFunction} />
<ImageBackground source={{uri: this.state.imageURI}} style={{
width: 200,
height: 300,
marginTop: 5,
alignItems: 'center',
justifyContent: 'center'
}}>
<Text style={{color: 'white'}}>{this.state.text}</Text>
</ImageBackground>
<View style={{ flexDirection: 'row', justifyContent: 'space-around' }}>
<View>
<DynamicText onChangeText={this.onTextReceived}/>
</View>
</View>
</View>
);
}
}
DynamicText.js:
import React, { Component } from 'react';
import { StyleSheet, Text, View, Image, Button, Platform, TouchableOpacity, TextInput, ImageBackground } from 'react-native';
export default class DynamicText extends Component {
constructor(props) {
super(props);
this.state = {
text: '',
mode: 1 // 1 = edit, 2 = view
}
}
onChange = (text) => {
this.setState({text});
this.props.onChangeText(text);
}
render() {
return (
<View ref="dymanicView">
<TextInput
ref="newItemText"
style={{ height: 40 }}
placeholder="Type something..."
onChangeText={(text) => this.onChange(text)}
/>
</View>
)
}
}
DynamicText.defaultProps = {
onChangeText: () => {}
}
I would like to understand about the defaultProps. For instance what does it do and when can I use it. Also please explain step by step the order of defining and transferring data between the components.
First of all, stackoverflow is not a platform for this type of question. You have to understand first by yourself and then still you have any doubt then put it with code. Anyways I'll explain how it will call when you run your project.
step-1:
first of all FilterView.js is loaded then load everything which you wrote in import tag and in render function.
step-2
then this.state is mutable. This means that state can be updated in the future while props can't. we can initialize state in the constructor, and then call setState when we want to change it.
step-3
then render method call which display what you want/write.
step-4
then captureScreenFunction is a function which you have to call onPress event of Button and onTextReceived is also a function which is call on onTextChange method.
function can bind in different ways but here captureScreenFunction is bind like this captureScreenFunction = () => {} or you can bind like this this.captureScreenFunction = this.captureScreenFunction.bind(this);
step-4
DynamicText.js file get data using this.props which is write in this file. In this file onChange = (text) => {} which calls onChangeText() function which is wrote inside FilterView.js using this.props.
and at last for default.props I'm giving you a link please refer this.
defaultProps in React Native?
Hope it will help you.

Image URI won't load when using setState

My <Image/> remains blank even though I am console logging the URI value.
I am getting the URI from an API. The URI I'm getting is definitely https as well.
My code looks like this:
constructor(props){
super(props)
this.state = {
img: ''
}
}
componentDidMount() {
this.getImage(this.props.id)
}
getImage(id){
_this = this;
fetch(`someURL${userId}`, {
method: 'get',
headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
})
.then(response => response.json())
.then((responseJson) => {
_this.setState({
img: responseJson.pic_url,
});
});
}
render() {
if (this.state.img) {
return (
<Image
resizeMode="cover"
style={{height: 50, width: 50}}
source={{uri: this.state.img}}
/>
}
return(
<View/>
)
}
If I just put the link into the URI directly like source={{uri: 'https://my-link'}} it works. I need to be able to use state though b/c the link is coming from my api.
I've created a snack expo with the following code:
import React, { Component } from 'react';
import { Image, Text, View, StyleSheet } from 'react-native';
import { Constants } from 'expo';
export default class App extends Component {
constructor() {
super();
this.state = {
imageUri: '',
};
}
componentWillMount() {
const _this = this
fetch('https://jsonplaceholder.typicode.com/photos/1')
.then(res => res.json())
.then(json => {
_this.setState({
imageUri: json.url.replace('http', 'https')
});
})
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Image Test!
</Text>
{
this.state.imageUri ? (
<Image
resizeMode="cover"
source={{uri: this.state.imageUri}}
style={{height: 200, width: 200}}
/>
) : null
}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
});
And it works just fine. The url that I get from the API is http, so I had to change it to https because it wouldn't work otherwise. Maybe that is your problem.
replace this
source={uri: this.state.img}
with
source={{uri: this.state.img}} // it will work if path is proper
So you are actually getting the response from your API? Did you print your URL inside your fetch method?
You don't need _this = this; as arrow functions are already binding this. However I think it shouldn't be a problem.
You have a mistake in your fetch.then
It should be:
.then( (response) => response.json())
You missed the brackets around response