React Native - Using objects from Custom Hooks - react-native

I'm trying to get screen dimensions from a custom hook but I don't know how to use the results from the imported component.
Obviously I could use {MyDims.Width} and {MyDims.Height} to display the results but for my final script I need to use the 2 objects as strings, hence the useState().
Here is the imported component: getdimensions.js
import React, {
useState,
useEffect
} from "react";
import {
Dimensions
} from "react-native";
function App(props) {
const [Width, setWidth] = useState(0)
const [Height, setHeight] = useState(0)
const getDims = () => {
setWidth(Dimensions.get("screen").width)
setHeight(Dimensions.get("screen").height)
}
useEffect(() => {
getDims()
}, []);
return {Width, Height}
}
export default App;
And the main screen: App.js
import React, {
useState,
useEffect,
} from "react";
import { Text, View, StyleSheet } from 'react-native';
import useDimensions from './components/getdimensions';
export default function App() {
const MyDims = useDimensions()
const [ShowMyDims, setShowMyDims] = useState({
width: MyDims.Width,
height: MyDims.Height
})
return (
<View style={styles.container}>
<Text style={styles.paragraph}>
width: {ShowMyDims.width} and
height: {ShowMyDims.height}
</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: 50,
backgroundColor: '#ecf0f1',
padding: 8,
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
});

You can return it as an array to avoid it being object. To get the updates from your custom hook to your component useState, add useEffect and trigger state updates upon change in Width, Height from your custom hook.
// In your hook component
...
return [Width, Height];
// In main component
...
const [Width, Height] = useDimensions();
const [ShowMyDims, setShowMyDims] = useState({ width: Width, height: Height });
// Add a useEffect hook to listen the updates
useEffect(() => {
setShowMyDims({ width: Width, height: Height });
}, [Width, Height])
....
You have an option of directly using Width, Height from your custom hook into your component without having an intermediate useState.

Related

How to hide splash screen in react native build using expo

My app is not loading after splash screen. It just stuck there.
So I added expo-splash-screen and still is not passing the splash screen. Before adding splash screen everything was working fine :(
See this is my App.js code. As you can see it only holds the navigation container which holds the links to other screens including the main home screen.
import {StatusBar } from 'expo-status-bar';
import { StyleSheet } from 'react-native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import { MaterialIcons } from "#expo/vector-icons";
import { HomeNavigator } from './CustomNavigation';
import * as Font from 'expo-font';
import * as SplashScreen from 'expo-splash-screen';
import { NavigationContainer } from '#react-navigation/native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import FavouritesScreen from './src/screens/FavouritesScreen'
import HomeScreen from './src/screens/HomeScreen';
import MoreOptions from './src/screens/MoreOptions'
import React, { useEffect, useState } from 'react'
console.reportErrorsAsExceptions = false; //to hide touch warning
const Stack = createNativeStackNavigator()
const Tab = createBottomTabNavigator();
SplashScreen.preventAutoHideAsync();
export default function App() {
const [fontLoaded, setFontLoaded] = useState(false)
const [appIsReady, setAppIsReady] = useState(false);
useEffect(() => {
async function prepare() {
try {
await Font.loadAsync(Entypo.font);
await new Promise(resolve => setTimeout(resolve, 2000));
} catch (e) {
console.warn(e);
} finally {
// Tell the application to render
setAppIsReady(true);
}
}
prepare();
}, []);
const onLayoutRootView = useCallback(async () => {
if (appIsReady) {
await SplashScreen.hideAsync();
}
}, [appIsReady]);
if (!appIsReady) {
return null;` `
}
return (
<View
style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}
onLayout={onLayoutRootView}>
<StatusBar barStyle="dark-content" hidden={false} backgroundColor="#ff3b3b" translucent={true} />
<NavigationContainer>
//it contains nothing but the navigation code
</NavigationContainer>
</View>)
Please tell me where and what I'm doing wrong here.
I give you the working example please check it
then after you don't understand let me know
code
import React, { useRef, useEffect } from 'react';
import { StyleSheet, View, Image, StatusBar, Text } from 'react-native';
/**
* RN libraries
*/
import { useNavigation } from '#react-navigation/native';
export default function Splash() {
const animation = useRef(null);
const navigation = useNavigation();
useEffect(() => {
animation.current?.play();
navigation.addListener('focus', () => {
animation.current?.play();
});
setTimeout(() => {
navigate();
}, 2500);
}, []);
const navigate = () => {
navigation.navigate('Home');
};
return (
<View style={styles.animationContainer}>
<Text
style={{
textAlign: 'center',
fontSize: 50,
fontStyle: 'italic',
fontFamily: 'Poppins-Medium',
fontWeight: '800',
color: '#fff',
}}>
Online{'\n'}Education
</Text>
<Text
style={{ color: '#fff', fontSize: 20, fontFamily: 'Poppins-Medium' }}>
Free{'\n'}
</Text>
<View
style={{
backgroundColor: '#5D6CFA',
width: 169,
height: 117,
borderRadius: 60,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
}}>
{/* <Text style={{color:"#000",fontFamily:'Poppins-Bold',fontSize:25}}>Let's start</Text> */}
</View>
</View>
);
}
const styles = StyleSheet.create({
animationContainer: {
backgroundColor: '#000',
alignItems: 'center',
justifyContent: 'center',
flex: 1,
},
});
Maybe pass your setAppIsReady(true); after the finally and then remove it like this
React.useEffect(() => {
async function prepare() {
try {
// Pre-load fonts, make any API calls you need to do here
AsyncStorage.setItem("alreadyAppLaunched", "true")
await LoadFonts()
await checkOsDarkMode()
await stores.AuthStore.getAllData()
} catch (e) {
console.warn(e);
}
setReady(true);
}
prepare()
}, [])

REACT NATIVE. How to dim the background of the bottomsheet?

I am trying to dim the background of this bottomSheet when it is activated or being rendered in the screen.
Also how do you make sure the bottomsheet disappears from the screen when the user touches the part of the screen that is not covered by the bottomSheet when it is active?
This is the code in app.js
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, View, ImageBackground, Text } from 'react-native';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { TouchableOpacity } from 'react-native';
import BottomSheet from './components/BottomSheet';
import { useCallback, useRef } from 'react';
import Volcano from './Images/Volcano.jpg'
export default function App() {
const firstRef = useRef (null)
const onPress = useCallback (() => {
const isActive = firstRef?.current?.isActive1();
if (isActive) {
firstRef?.current?.scrollTo(35);
} else {
firstRef?.current?.scrollTo(-200);
}
})
return (
<GestureHandlerRootView style={{flex:1}}>
<ImageBackground source={Volcano} resizeMode='repeat' style={{
flex: 1,
width : '100%',
// flexDirection: 'column',
justifyContent: 'center',
}}>
<StatusBar style="auto" />
<TouchableOpacity style={{
height:50,
width: '10%',
backgroundColor:'green',
aspectRatio:1,
borderRadius:25,
opacity:.6,
marginLeft:360,
}} onPress={onPress}/>
<BottomSheet ref={firstRef}/>
</ImageBackground>
</GestureHandlerRootView>
);
};
This is the one in the bottomsheet.js
import { Dimensions, StyleSheet, Text, View } from 'react-native'
import React, { useCallback, useImperativeHandle } from 'react'
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import Animated, { event, Extrapolate, interpolate, useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated';
const {height: SCREEN_HEIGHT} = Dimensions.get('window');
const MAX_TRANSLATE_Y = -SCREEN_HEIGHT + 50;
const BottomSheet = React.forwardRef(({},ref) => {
const translateY = useSharedValue(35);
const active = useSharedValue()
const scrollTo = useCallback ((destination = Number) =>{
'worklet';
active.value = destination !== 35;
translateY.value = withSpring(destination, {damping:15});
}, []);
const isActive1 = useCallback (()=> {
return active.value;
},[])
useImperativeHandle(ref, () => ({scrollTo, isActive1}), [scrollTo, isActive1]);
const updatePan = useSharedValue({y:0});
const activateGesture = Gesture.Pan()
.onStart(() => {
updatePan.value = { y:translateY.value};
})
.onUpdate((e) => {
translateY.value = e.translationY + updatePan.value.y;
translateY.value = Math.max(translateY.value, MAX_TRANSLATE_Y);
})
.onEnd (() => {
if (translateY.value > -SCREEN_HEIGHT/3){scrollTo(35) ;
} else if (translateY.value < -SCREEN_HEIGHT / 1.5) {
scrollTo(MAX_TRANSLATE_Y)
}
});
const rBottomSheetStyle = useAnimatedStyle (() => {
const borderRadius = interpolate(
translateY.value,
[MAX_TRANSLATE_Y + 100, MAX_TRANSLATE_Y],
[25, 5],
Extrapolate.CLAMP
);
return {
borderRadius,
transform: [{ translateY: translateY.value }],
};
});
return (
<GestureDetector gesture={activateGesture}>
<Animated.View
style= {[styles.bottomSheetContainer, rBottomSheetStyle]}
>
<View style={styles.line} />
</Animated.View>
</GestureDetector>
)
})
const styles = StyleSheet.create({
bottomSheetContainer: {
height: SCREEN_HEIGHT,
width:'100%',
backgroundColor: 'white',
position: 'absolute',
top: SCREEN_HEIGHT,
borderRadius: 25,
},
line:{
width: 75,
backgroundColor: 'grey',
height: 4,
alignSelf: 'center',
marginVertical: 15,
borderRadius:2,
}
})
export default BottomSheet
As you can see on the image the background is not dim when the bottomsheet is activatted.
[1]: https://i.stack.imgur.com/RdEzm.jpg
Please assist

React Native Snap Carousel Functional Component Issue

I'm using this snack as a template for implementing my own carousel component. This template is using Class Component and I converted it to a Functional component
https://snack.expo.io/#bd-arc/react-native-snap-carousel-%7C-example-with-custom-interpolations
I added this to my project and I believe some error is happening when rendering the Carousel but I'm unable to tell. It renders - but not all the components are rendering. I have only changed the Carousel itself to a function component. The problem is the is not showing below the Carousel - also if I add multiple VideoCarousel's, only the first one displays.
My code is below
App.js
import React from 'react';
import { View } from 'react-native';
import Header from './components/header';
import VideoCarousel from './components/videoCarousel';
import tailwind from 'tailwind-rn';
const App = () => {
return (
<View style={tailwind('flex pt-12 items-center bg-gray-300 h-full')}>
<Header />
<VideoCarousel />
<VideoCarousel />
</View>
)
};
export default App;
VideoCarousel.js
import React, { useState } from 'react';
import { Text, View, Dimensions, StyleSheet, Alert } from 'react-native';
import Carousel from 'react-native-snap-carousel'; // Version can be specified in package.json
import { scrollInterpolator, animatedStyles } from './../utils/animations';
const SLIDER_WIDTH = Dimensions.get('window').width;
const ITEM_WIDTH = Math.round(SLIDER_WIDTH * 0.7);
const ITEM_HEIGHT = Math.round(ITEM_WIDTH * 3 / 4);
const DATA = [];
for (let i = 0; i < 10; i++) {
DATA.push(i)
}
const VideoCarousel = () => {
const [index, setIndex] = useState(0);
_renderItem = (index) => {
return (
<View style={styles.itemContainer}>
<Text style={styles.itemLabel}>{`Item ${index.index}`}</Text>
</View>
);
}
return (
<View>
<Carousel
data={DATA}
renderItem={this._renderItem}
sliderWidth={SLIDER_WIDTH}
itemWidth={ITEM_WIDTH}
containerCustomStyle={styles.carouselContainer}
inactiveSlideShift={0}
onSnapToItem={(index) => setIndex(index)}
scrollInterpolator={scrollInterpolator}
slideInterpolatedStyle={animatedStyles}
useScrollView={true}
/>
<Text style={styles.counter}>
Test
</Text>
</View>
);
}
const styles = StyleSheet.create({
carouselContainer: {
marginTop: 50
},
itemContainer: {
width: ITEM_WIDTH,
height: ITEM_HEIGHT,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'dodgerblue'
},
itemLabel: {
color: 'white',
fontSize: 24
},
counter: {
marginTop: 400,
fontSize: 30,
fontWeight: 'bold',
textAlign: 'center',
backgroundColor: "black",
}
});
export default VideoCarousel;

How can I get the text / value of a textinput by its ref?

In my parent I have this code:
So I render inside it my custom inputs by this way:
My doubt is how I can access on any part of this parent the text of each input using the ref. Someone can help me?
The textinput component:
https://gist.github.com/ThallyssonKlein/4e054bc368ebc153fbf9222e304ff887
I couldn't solve the problem, apparently there is no way to get this property in pure React-Native.
So I started using the TextInput component of the react-native-paper package. This way the same code worked, I can get the text now with this excerpt:
console.log(refContainerStep1.current.state.value);
use useRef() instead of createRef();
const textInput = useRef(null);
<TextInput
ref={textInput}
....../>
You can access the ref via refContainerStep1.current.
What you can then do is check the Prototype property to check which methods you can use.
I noticed there's a function called _getText which can be used to obtain a value.
An example of grabbing the value in an onPress:
const onPress = () => {
console.log(refContainerStep1.current.__proto__); // See available methods
console.log(refContainerStep1.current._getText()); // Grab the value
}
Do it that way
const onButtonClick = () => {
console.log('get value from parent')
console.log(ref1.current.props.value)
console.log(ref2.current.props.value)
};
Example in expo
Parent
import * as React from 'react';
import { Text, View, StyleSheet,TextInput } from 'react-native';
import Constants from 'expo-constants';
import MyTextInput from './components/AssetExample';
import { Card } from 'react-native-paper';
export default function App() {
const ref1 = React.createRef();
const ref2 = React.createRef();
const onButtonClick = () => {
console.log(ref1.current.props.value)
console.log(ref2.current.props.value)
};
return (
<View style={styles.container}>
<Card>
<button onClick={onButtonClick}>get value</button>
<MyTextInput label={'label 2'} secure={false} ref={ref1} />
<MyTextInput label={'label 1'} secure={true} ref={ref2} />
</Card>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
});
Child
import React, { useState, useEffect } from 'react';
import { TextInput as RnTextInput, StyleSheet, View, Text } from 'react-native';
const styles = StyleSheet.create({
textInput: {
padding: 10,
marginRight: 10,
marginLeft: 10,
borderRadius: 50,
},
text: {
marginLeft: 20,
marginBottom: 10,
fontSize: 20,
},
});
const TextInput = React.forwardRef((props, ref) => {
const [text, setText] = useState('');
return (
<View>
{props.label && <Text style={styles.text}>{props.label}</Text>}
<RnTextInput
style={styles.textInput}
value={text}
onChange={(e) => {
setText(e.target.value);
}}
secureTextEntry={props.secure}
ref={ref}
/>
</View>
);
});
export default TextInput;

Reset Animation for Animted React Native

I've stumbled upon a problem when trying to use resetAnimation() in React Native.
I'm trying to build an animated.view that resets when a new view is displayed on a touchablewithoutfeedback component.
I cannot figure out how to reset the animation so that when I press my touchablewithoutfeedback the animation resets and starts again for the new that is displayed. It runs on the first render but then it stops and just displays the text normally.
Here are some snippets of my code.
import React, { useState, useEffect } from 'react';
import { Animated, StyleSheet } from 'react-native';
const FadeView = (props) => {
const [fadeAnim] = useState(new Animated.Value(0)); // Initial value for opacity: 0
React.useEffect(() => {
Animated.timing(
fadeAnim,
{
toValue: 1,
duration: 1000,
}
).start(fadeAnim.resetAnimation())
}, []);
return (
<Animated.View // Special animatable View
style={{
...props.style,
opacity: fadeAnim, // Bind opacity to animated value
}}
>
{props.children}
</Animated.View>
);
}
const styles = StyleSheet.create({
view:{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
// You can then use your `FadeInView` in place of a `View` in your components:
export default FadeView;
And where i try to use it.
<FadeView>
<Text style = {styles.gameText}> {question} </Text>
</FadeView>
I managed to solve it by removing the
, []
at the end of ).start(fadeAnim.resetAnimation())
}, []);
and adding
fadeAnim.resetAnimation();
after that codeblock.