URL not updated on NavigationStateChange react-native web-view - react-native

<WebView
ref={webView => { this.refWeb = webView; }}
style={{
height:height,
justifyContent: 'center',
alignItems: 'center',
}}
scrollEnabled={true}
//Loading URL
source={
{
uri: initialUrl,
}
}
//Enable Javascript support
javaScriptEnabled={true}
domStorageEnabled={true}}
injectedJavaScript={injectScript}
automaticallyAdjustContentInsets = {true}
startInLoadingState={true}
onNavigationStateChange={this.onNavigationStateChange}/>
onNavigationStateChange = (navState) => {
console.log(navState);
if(navState.url===initialUrl){
this.setState({
canGoBack: navState.canGoBack,
canGoForward: navState.canGoForward,
changedUrl:false
})
}else{
this.setState({
canGoBack: navState.canGoBack,
canGoForward: navState.canGoForward,
changedUrl : true
})
}
}
I am using react-native-webview but onNavigationStatechange not updating navState url it remains same when i click internal links inside webview.
Also got to know some issue due to Single Page Application, Can anyone suggest the approach to handle and overcome this problem.

Related

React Native - unable to change font when secureTextEntry is set

const entryInput = forwardRef((props, ref) => {
return (
<View
style={{
fontFamily: "roboto-regular",
color: "rgba(255,0,0,0.6)",
fontSize: hp("1.5%")
}}>
<Text style={styles.text}>{props.show_err ? props.err : null}</Text>
<TextInput
ref={ref}
style={{
borderColor:
!props.err || props.err === "" || props.err === props.empty_err
? "gray"
: "rgba(255,0,0,0.6)",
backgroundColor: "rgba(213, 213, 213, 0.1)",
borderWidth: wp("0.3%"),
borderRadius: wp("1%"),
width: wp("85%"),
height: hp("5.2%"),
fontFamily: "roboto-regular",
fontSize: hp("2%"),
fontWeight: "normal"
}}
returnKeyType={props.last ? "done" : "next"}
blurOnSubmit={props.last ? true : false}
placeholderTextColor={"gray"}
paddingLeft={wp("2%")}
paddingRight={hp("2%")}
placeholder={props.placeholder}
onSubmitEditing={() => {
if (props.next_input) {
props.next_input.current.focus();
} else if (props.action) {
props.action();
}
}}
onChangeText={(text) => {
if (props.setText) props.setText(text);
if (props.validate) props.validate(text);
}}
/>
</View>
);});
New to react native... trying to create an input field for a password.
This custom component works great, but when I add the secureTextEntry={true} the font changes for no reason (it's not roboto-regular), it doesn't even change to the default font.
I noticed that when I remove the fontFamily key from the style object then save my code and the expo client reloads, then add fontFamily again and reload again the TextInput behaves as expected and the font is the one I set (roboto-regular), however the bug reappears when manually reloading the app.
The accepted answer will work on luck. The refs can be both defined or undefined when the component is being mounted.
Add the following to your component to properly solve the issue:
const _inputRef = useRef(null);
const setRef = useCallback((node) => {
if (_inputRef.current) {
// Make sure to cleanup any events/references added to the last instance
}
if (node) {
// Check if a node is actually passed. Otherwise node would be null.
// You can now do what you need to, setNativeProps, addEventListeners, measure, etc.
node.setNativeProps({
style: { fontFamily: "Quicksand-Medium" },
});
}
// Save a reference to the node
_inputRef.current = node;
}, []);
Make sure your TextInput has this ref assigned:
<TextInput ref={setRef} ... />
Adding the following to my custom component fixed the problem:
useEffect(() => {
if (ref) {
ref.current.setNativeProps({
style: { fontFamily: "roboto-regular" }
});
}
}, []);

How do I pause a playing video (played with react-native-video) when user scrolls to another page in a viewpager (#react-native-community/viewpager)?

In my app I am using a ViewPager (#react-native-community/viewpager) to display several pages. Some of these pages contain videos that I am displaying using react-native-video. If I start a video on one page and then scroll to the next page the video keeps playing in the background. The user can hear the audio of the video although the audio is not visible.
I would like to pause the video when the user scrolls to the next page, how do I accomplish that?
You can store the current page value in state and set some indexes to your pages, like in example below. After that just check if your page is current page:
<ViewPager
initialPage={0}
onPageScroll={({ nativeEvent }) => {
this.setState({
activePage: nativeEvent.position
})
}
}>
<View key="1">
<Video source={{ uri: '' }}
paused={this.state.activePage !== 0} />
</View>
<View key="2">
<Video source={{ uri: '' }}
paused={this.state.activePage !== 1} />
</View>
</ViewPager>
EDIT:
If you do not need the video to auto-start, you can add isPlaying property in state, and set it to true when you need.
<ViewPager
initialPage={0}
onPageScroll={({ nativeEvent }) => {
this.setState({
activePage: nativeEvent.position,
isPlaying: false
})
}
}>
<View key="1">
<Video source={{ uri: '' }}
paused={!this.state.isPlaying || this.state.activePage !== 0} />
</View>
<View key="2">
<Video source={{ uri: '' }}
paused={!this.state.isPlaying || this.state.activePage !== 1} />
</View>
</ViewPager>
You can check index of ViewPage with index of VideoItem when you map data.
Example:
<ViewPager
onPageSelected={this.onPageSelected}
initialPage={currentVisibleIndex}
style={{ width: '100%', height: '100%', justifyContent: 'center' }}
key={data.length}
// onPageScroll={this.onPageScroll}
scrollEnabled={data && data.length > 1}
// onPageScrollStateChanged={this.onPageScrollStateChanged}
>
{data.map((item, i) => {
if (isVideo(item)) {
return (
<VideoItem
uri={item}
key={i.toString()}
currentVisibleIndex={currentVisibleIndex}
currentIndex={i}
/>
);
}
return (
<ImageItem
uri={item}
defaultSource={Images.defaultImageAlbum}
key={i.toString()}
/>
);
})}
</ViewPager>
And in VideoItem.js you can use this to paused video when you scroll viewpager.
static getDerivedStateFromProps(props, state) {
let { paused } = state;
if (props.currentVisibleIndex !== props.currentIndex) {
paused = true;
}
return {
paused,
currentVisibleIndex: props.currentVisibleIndex
};
}
Sorry about my English.

Expo Video re-render on state change

I have a video where all I want it a play button over the top. I have achieved this with the following:
<View style={{ backgroundColor: 'yellow', justifyContent: 'center', alignItems: 'center'}}>
<Video
ref={setupVideo}
source={require('../../assets/AppSampleCoverVideo.mp4')} // TODO:
rate={1.0}
volume={1.0}
isMuted={false}
shouldPlay={isPlaying}
resizeMode='contain'
isLooping={false}
style={styles.setupVideo}
//onPlaybackStatusUpdate={onPlaybackStatusUpdate}
//useNativeControls={true}
/>
<TouchableOpacity style={styles.playButton} onPress={toggleVideoPlay}>
{
!isPlaying ? (
<Ionicons style={styles.playIcon} color='white' size={ Dimensions.get('window').width / 5 } name='ios-play' />
) : null
}
</TouchableOpacity>
</View>
I control the video with the following:
const [isPlaying, setIsPlaying] = useState(false)
const setupVideo = useRef(null);
const toggleVideoPlay = async () => {
try {
let videoStatus = await setupVideo.current.getStatusAsync();
if(videoStatus.isPlaying) {
return setupVideo.current.pauseAsync();
} else {
if(videoStatus.durationMillis === videoStatus.positionMillis) return setupVideo.current.replayAsync();
return setupVideo.current.playAsync();
}
} catch(err) {
}
}
However, I want to be able to track when the video is playing and when it is not in order to set the isPlaying and control whether the play button icon is rendered or not. Anything I have tried causes either the video to flicker when calling setIsPlaying or the video re-renders and doesn't play at all.
Any help would be appreciated.

How to show loading icon in react native until the API response in react native?

I am creating a new app. After tapping the submit button I want to show the loading icon in the login page until the API response. Please help me
First create a state variable for showing and hiding loader as follows
this.state = {
..
loading: false,
..
};
In the api call before the request send, you can set loading state to true and after completing the response set it to false
getData() {
this.setState({loading:true});// For showing loader
axios.get('api_link_goes_here')
.then(response => {
this.setState({loading:false});// For hiding loader
console.log(response.data);
})
.catch(error => {
this.setState({loading:false});// For hiding loader
console.log(error);
});
}
In your render template, you can add a View for showing the loader based on the state, You can add it to the bottom and position and make it full screen to avoid further clicks until response is received
render() {
return (
<View style={container}>
.....
{this.state.loading === true &&
<View style={styles.myloader}>
<CustomLoader /> // You can define this in another component or simply write <Text>Please wait...</Text>
</View>
}
....
</View>
)}
Style is given below for loader container
const styles = StyleSheet.create({
.....
myloader: {
position: "absolute",
top: 0,
left: 0,
zIndex: 10,
backgroundColor: "#ffffff",
opacity: 0.9,
justifyContent: 'center',
alignItems: 'center',
width: "100%",
height: "100%"
}
...
});

React Native: I am getting error while trying to get image from https://cataas.com api

I am getting SyntaxError: Json Parse error: JSON Parse error: Unrecognized token '<'
I'm using https://cataas.com api for a react native app, my task is to generate a list of random kitten images. I tried using fetch method, but also i get error sorce.uri should not be an empty string. How can i solve this problem?
Here is my code:
import React, { Component } from 'react';
import {
Image,
StyleSheet,
Text,
View,
FlatList
} from 'react-native';
class App extends Component {
state = {
photos: '',
}
componentDidMount() {
fetch('https://cataas.com/cat?width=100')
.then(res => res.json())
.then(data => {
this.setState({
photos: data
})
.catch(err => {
console.log('error', err);
alert(err)
})
})
}
render() {
console.log(this.state.photos)
return (
<View style={styles.container}>
<Image
source={{url: this.state.photos}}
style={{height: 100, width: 100}}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#ecf0f1',
}
});
export default App;
There is a typo in your code
Replace url with uri as in the docs
<Image
source={{uri: this.state.photos}}
style={{height: 100, width: 100}}
/>
You don't have to call this api manually, you could directly use the link in the Image component :
<Image
source={{uri: "https://picsum.photos/100/100"}}
style={{height: 100, width: 100}}
/>
EDIT:
Ok it's not as easy as I thought !
I created a first basic version : https://snack.expo.io/#sanjar/so-53434400
And contrary to what I thought it's always the same picture that is displayed.
It's because of react-native cache system that see the same url and decide to not execute the http request again.
then I checked the doc and founda way to fix this issue, but for ios only
I just had to change :
source={{uri: "https://source.unsplash.com/random"}}
by :
source={{uri: "https://source.unsplash.com/random", cache: 'reload'}}
It should work on ios (I don't have a mac with me now), for android I don't know yet, I'll probably investigate later.