Show loading indicator between navigation of pages in a Webview - reactjs

I have a url in the Webview like https://www.nytimes.com/ The current code works inital page load but If I type tap anything in the link, the page takes a while to load and there are no loading indicators in the website. Is there any way we can put a page loading indicator in React Native while we click on any link or page loading specially if it is server side rendered like next js?
Here is my ReactNative code.
import * as React from 'react';
import {
View,
Text,
Image,
SafeAreaView,
ScrollView,
TextInput,
TouchableOpacity,
} from 'react-native';
import styles from './styles';
import { WebView } from 'react-native-webview';
// import WelcomeSwiper from '../../components/WelcomeScreen/WelcomeSwiper';
import LoadingIcon from '../../components/Loading/index.js';
const WebView = ({ navigation }) => {
return (
<SafeAreaView style={styles.container}>
<WebView
javaScriptEnabled={true}
domStorageEnabled={true}
renderLoading={LoadingIcon}
source={{ uri: 'https://www.nytimes.com/ ' }}
startInLoadingState={true}
/>
</SafeAreaView>
);
};
export default WebView;
Here is my loading component
import React from 'react';
import { StyleSheet, Platform, ActivityIndicator } from 'react-native';
const LoadingIcon = () => {
return (
<ActivityIndicator
color='#009688'
size='large'
style={styles.ActivityIndicatorStyle}
/>
);
}
export default LoadingIcon;
const styles = StyleSheet.create(
{
WebViewStyle:
{
justifyContent: 'center',
alignItems: 'center',
flex: 1,
marginTop: (Platform.OS) === 'ios' ? 20 : 0
},
ActivityIndicatorStyle: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
alignItems: 'center',
justifyContent: 'center'
}
});

we can use these two approaches to get the result:
You can check if the WebView is loading something or not with the onLoadProgress method. This method gives you a number between 0 and 1. If the page is fully loaded it will return number 1, update your state and show the ActivityIndicator according to it:
you can use onLoadStart and onLoadEnd to update your state and show the ActivityIndicator according to it!
for more info check the: https://github.com/react-native-community/react-native-webview/blob/master/docs/Reference.md#onloadprogress
you can also use your ActivityIndicator wrapped by WebView, *do not Forget this method works in ios for android put it outside of WebView
and this is a working code sample for you:
import React, {useState} from 'react';
import {View, Text, SafeAreaView, ActivityIndicator} from 'react-native';
import {WebView} from 'react-native-webview';
function WebViewTest() {
const [isLoading, setLoading] = useState(false);
return (
<SafeAreaView style={{flex: 1}}>
<WebView
source={{uri: 'https://www.nytimes.com/'}}
onLoadStart={(syntheticEvent) => {
setLoading(true);
}}
onLoadEnd={(syntheticEvent) => {
setLoading(false);
}} />
{isLoading && (
<View style={{flex: 10, backgroundColor: 'white'}}>
<ActivityIndicator
color="#009688"
size="large"
// style={{position: 'absolute', left: 200, top: 300}}
/>
</View>
)}
</SafeAreaView>
);
}
export default WebViewTest;
I hope it helps

I use onLoadProgress to solve this issue.
renderLoading function is just called at the initial loading state of webview component. Using renderLoading is not helpful to show activity indicators at any tap on page links or navigating between webview pages.
Checking onLoadStart and onLoadEnd is useful in android but in iOS onLoadEnd is not called in the back navigation gesture which results in endless spinning of activity indicator.
onLoadProgress returns a number between 0-1 while webview is in the loading state. You check its progress state and update your activity indicator state.
For more information about onLoadProgress: onLoadProgress
Here is a working code example for you:
import React, {useState} from 'react';
import {View, Text, SafeAreaView, ActivityIndicator} from 'react-native';
import {WebView} from 'react-native-webview';
function WebViewTest() {
const [isLoading, setLoading] = useState(false);
return (
<SafeAreaView style={{flex: 1}}>
<WebView
source={{uri: 'https://www.nytimes.com/'}}
onLoadProgress={({nativeEvent}) => {
if (nativeEvent.progress != 1 && isLoading == false ) {
setLoading(true)
} else if (nativeEvent.progress == 1 ) {
setLoading(false)
}
}}
/>
{isLoading && (
<View style={{flex: 10, backgroundColor: 'white'}}>
<ActivityIndicator
color="#009688"
size="large"
// style={{position: 'absolute', left: 200, top: 300}}
/>
</View>
)}
</SafeAreaView>
);
}
export default WebViewTest;

Related

Change Image on Click in React Native

I am trying to create an app that changes to one of many images when the image is clicked. I have used touchable opacity and can make the image show an alert when clicked. I just can't get it to change to one of the many others in the file.
Here is all my code so far:
import React from 'react';
import { Component, Stylesheet, useState, TouchableOpacity, Button, View, Text, Image, ScrollView, TextInput, Alert } from 'react-native';
// main part of the app
const App = () => {
var array = [require("./cards/card.png"), require("./cards/card2.png")]
var x = 0
//onclick function
const handlePress = () => {
//some logic
alert("help")
x+=1
}
// what shows up on the app
return (
<ScrollView>
<View>
<Text>{array[x]}</Text>
<Text>{x}</Text>
<View style={{ flexDirection: 'row', justifyContent: 'center' }}>
<TouchableOpacity
onPress={(handlePress)}
>
<Image
style={{
width: 300,
height: 300,
}}
resizeMode="contain"
source={
array[x]
}
/>
</TouchableOpacity>
</View>
</View>
</ScrollView>
);
}
export default App;
The other images that I want the card to change to are in the cards folder. What do I do to make it dynamic and change it to any of the other cards in the folder?
in order to change image or any information in a screen that have been mounted, React have to re-render the screen and put the right information that you want.
To achieve this, you should use React states https://reactnative.dev/docs/state
Your code could be like this:
import React from 'react';
import { Component, Stylesheet, useState, TouchableOpacity, Button, View, Text, Image, ScrollView, TextInput, Alert } from 'react-native';
// main part of the app
const App = () => {
const [card, setCard] = useState(0); //initial state
var array = [
"./cards/card.png",
"./cards/card2.png"
]
//onclick function
const handlePress = () => {
//some logic
//set card state to the next index
setCard( current => current + 1);
//so everytime you click function the state will change and this re-render your component with the new data.
}
// what shows up on the app
return (
<ScrollView>
<View>
<Text>{array[card]}</Text>
<View style={{ flexDirection: 'row', justifyContent: 'center' }}>
<TouchableOpacity
onPress={(handlePress)}
>
<Image
style={{
width: 300,
height: 300,
}}
resizeMode="contain"
source={ require(array[card]) }
/>
</TouchableOpacity>
</View>
</View>
</ScrollView>
);
}
export default App;

Lottie Animation showing with no colour React Native

I have Lottie React Native working perfectly in my project except for one minor issue. The colour of the animation is not appearing and I cannot seem to identify what the cause is here. The component is very simple
import React from 'react';
import {StyleSheet, View, Text} from 'react-native';
const styles = StyleSheet.create({
text: {
fontFamily: 'Roboto-Bold',
fontSize: 18,
},
});
export default (props) => {
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<Text style={styles.text}>Login Screen</Text>
</View>
);
};
Can see here in this that the background of the animation is white when it should have a background colour set: https://lottiefiles.com/7825-money-transfer. Any thoughts/guidance is appreciated.
Here is the working example
Snack link: https://snack.expo.io/#msbot01/forlorn-raspberries
import React, { Component } from 'react';
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
import LottieView from 'lottie-react-native';
export default class NoNetwork extends Component {
render() {
return (
<View style={{ flex: 1, backgroundColor:'green' }}>
<LottieView source={require('./pay.json')} autoPlay loop />
</View>
);
}
}
const styles = StyleSheet.create({});

React Native: Dispatching action to fetch data before rendering (Redux)

I'm developing a react native app with redux as a state management and trying the following implementation:
Fetching data from Server (Firebase) before rendering the app. I have a loading screen, which is working fine, but i cant dispatch my function in it for fetching the data from server and write directly to the current state. I dont see that the state is changed, but when I saving the code (as it is) again the state is updated as I expected. So i think my code is fetching the data after the first rendering is done.
I cant figure out the the problem. Cause i put my code for dispatching in the "useeffect" hook as i should or not?
import React, {useEffect} from 'react';
import {ActivityIndicator, View} from 'react-native';
import {Images, useTheme} from '#config';
import {Image, Text} from '#components';
import styles from './styles';
import {ApplicationActions} from '#actions';
import { store } from '/Users/user1/KitaList/app/store/index.js'
export default function Loading({navigation}) {
const {colors} = useTheme();
const onProcess = () => {
setTimeout(() => {
navigation.replace('Main');
}, 2500);
};
useEffect(() => {
store.dispatch(ApplicationActions.ongetKitadata()); //Executing dispatchting getting data
onProcess();
}, []);
return (
<View style={styles.container}>
<View style={{alignItems: 'center'}}>
<Image source={Images.logo} style={styles.logo} resizeMode="contain" />
<Text title1 style={{marginTop: 10}}>
MyApp
</Text>
<Text headline primaryColor style={{marginTop: 10}}>
MyApp DIRECTORY
</Text>
</View>
<ActivityIndicator
size="large"
color={colors.text}
style={{
position: 'absolute',
top: 260,
left: 0,
right: 0,
bottom: 0,
justifyContent: 'center',
alignItems: 'center',
}}
/>
</View>
);
}

How to play a segment of a Lottie Animation (.json file ) in React Native

I want to play only a segment of the animation in react native using lottie view
the length is about 5 seconds while in speed={1} I wanna play only the first 3 seconds and then go to the next screen
the code is down below
LogoScreen.js :
import React from 'react';
import { StyleSheet, View, Image, TextInput, StatusBar, Text } from "react-native";
import Icons from 'react-native-vector-icons/Ionicons';
import LottieView from "lottie-react-native";
export default class ChatScreen extends React.Component {
onAnimationFinish = () => {
this.props.navigation.navigate("Login")
}
render () {
return (
<View style={styles.container}>
<StatusBar barStyle="light-content" backgroundColor="#161f3d" />
<View>
<LottieView
source={require('../assets/animations/lottie/MotionCorpse-Jrcanest.json')}
style={{ justifyContent: "center", alignSelf: "center", height: "100%", width: "100%" }}
autoPlay
loop={false}
speed={1}
onAnimationFinish={this.onAnimationFinish}
/>
</View>
</View>
)
}
Well you can do it by several ways, one of the way would be like below.
You can use ref to play it manually and then after 3 seconds just redirect to next screen.
import React from 'react';
import { StyleSheet, View, Image, TextInput, StatusBar, Text } from "react-native";
import Icons from 'react-native-vector-icons/Ionicons';
import LottieView from "lottie-react-native";
export default class ChatScreen extends React.Component {
componentDidMount() {
this.anim.play();
setTimeout(() => {
this.props.navigation.navigate("Login")
}, 3000);
}
render() {
return (
<View style={styles.container}>
<StatusBar barStyle="light-content" backgroundColor="#161f3d" />
<View>
<LottieView
source={require('../assets/animations/lottie/MotionCorpse-Jrcanest.json')}
style={{ justifyContent: "center", alignSelf: "center", height: "100%", width: "100%" }}
autoPlay={false}
loop={false}
speed={1}
ref={animation => { this.anim = animation; }}
/>
</View>
</View>
)
}
}
Another way is if you know exact frame numbers then you can play animation till that frame which completes at 3 seconds. It is already mentioned in Lottie documentation.
this.animation.play(30, 120);

Simple React Native Image Game is Lagging.How do i optimize?

I am trying to implement a simple img tapping game with react native for learning purposes.I am using this librarys https://github.com/bberak/react-native-game-engine game loop component as a game loop.
What I am trying to do is render some imgs with random locations on screen with small radius then increase it up to a value, after decrease it and finally remove the img from screen (or when tapped) - just like in this game: http://mouseaccuracy.com/
import React, { Component } from "react";
import { AppRegistry, StyleSheet, Dimensions, View,ToastAndroid,TouchableOpacity,Image,Text } from "react-native";
const { width: WIDTH, height: HEIGHT } = Dimensions.get("window");
import { GameLoop } from "react-native-game-engine";
import { Fonts } from '../utils/Fonts';
import FastImage from 'react-native-fast-image'
import * as Progress from 'react-native-progress';
import SwordImage from "../assets/tapfight/sword.png";
import ShieldImage from "../assets/tapfight/shield.png";
this.renderSwordOrCircle(circle)
)
})
)
}
}
renderHealth = () =>{
return(
<View>
<View style={{ alignItems:'center' ,position: "absolute", top: 0, left: 0}}>
<Text style={{fontFamily:Fonts.MainFont,color:'white',fontSize:25}}>{this.playerHealth}</Text>
<Progress.Bar color='red' progress={this.playerHealth/100} width={100} height={18} />
</View>
<View style={{ alignItems:'center',position: "absolute", top: 0, right: 0}}>
<Text style={{fontFamily:Fonts.MainFont,color:'white',fontSize:25}}>{this.enemyHealth}</Text>
<Progress.Bar color='red' progress={this.enemyHealth/100} width={100} height={18} />
<FastImage resizeMode="contain" style={{width:100,height:100}} source={require('../assets/tapfight/guard_2_head.png')}></FastImage>
</View>
</View>
)
}
render() {
if(this.state.fight==true){
return (
<View style={{flex:1,backgroundColor:'transparent'}} >
<GameLoop style={{flex:1}} onUpdate={this.updateCircle}>
{this.renderHealth()}
{this.renderCircles()}
</GameLoop>
</View>
);
}else{
return(
null
)
}
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
}
});
What i am doing is i am generating images every 600 ms on screen and player tries to tap them.The problem is when there is more than 2 images on screen fps drops significantly.Tested in android actual device.I am updating state once at the end of updateCircle function.
Game loop is updateCircle component
Your problem is that you're trying to animate a component that is not made for being animated.
I dont know well the FastImage component, but I understand that it purpose is to pre-load images, not animate.
You shoud use Animated.Image for the image, and Animated.timing for managing the animations of Animated.Image

Resources