Why JS thread drops frames when using React Native Reanimated? - react-native

I'm not sure why JS thread drops frames when I'm toggling the height of the View when using react-native-reanimated v2? When I press the button JS frames are around 50-55 and UI thread fps stay 60. Thank you.
My code is pretty simple:
import React, {useEffect} from 'react';
import {
Button,
ImageBackground,
StatusBar,
StyleSheet,
Text,
ViewStyle,
} from 'react-native';
import Animated, {
useAnimatedStyle,
useSharedValue,
withTiming,
} from 'react-native-reanimated';
export const TestingScreen: React.FC<TestingScreenProps> = () => {
const height = useSharedValue(0);
const style = useAnimatedStyle(() => {
return {
height: withTiming(height.value),
};
});
return (
<>
<StatusBar barStyle="dark-content" />
<ImageBackground
style={styles.container}
source={require('./../../../assets/images/cinema.jpg')}
resizeMode={'cover'}>
<Animated.View style={[styles.form, style]}>
<View
style={{
width: 150,
height: 150,
backgroundColor: 'red',
}}></View>
</Animated.View>
<Button
title={'Toogle'}
onPress={() =>
(height.value =SCREEN_HEIGHT * Math.random())
}
/>
<Text
style={{fontSize: 23, color: 'white', fontFamily: 'OpenSans-Italic'}}>
TESTING
</Text>
</ImageBackground>
</>
);
};

I think this is because button pressing function (onPress prop) is in the JS side. So the pressing part happening in the JS thread. That's why JS frames drop when you hit the button.

Related

items doesnt stick to bottom react nativr

im trying to make a to-do list in react native and im trying to make the input and plus bar stick to the bottom and make it go up when i open the keyboard. when i use padding the bar sticks to bottom but i want to use flexbox to make it compatible with all phones. can someone help make stick it to bottom and make it go up with keyboard
task.js
import React from 'react';
import {View, Text, SafeAreaView, StyleSheet, TextInput,KeyboardAvoidingView, TouchableWithoutFeedback, TouchableOpacity} from 'react-native';
const AddTask = () => {
const handleAddTask = () => {
Keyboard.dismiss();
setTaskItems([...taskItems, task])
setTask(null);
}
return (
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
style ={styles.inputbuttons}
>
<TextInput style={styles.input} placeholder={'Write a task'} />
<TouchableOpacity onPress={() => handleAddTask()}>
<View style = {styles.plus}>
<Text>+</Text>
</View>
</TouchableOpacity>
</KeyboardAvoidingView>
);
};
const styles = StyleSheet.create({
input: {
height: 60,
width:320,
margin: 12,
borderWidth: 1,
padding: 10,
borderRadius:20,
},
inputbuttons:{
flexDirection:'row',
alignItems:'center',
justifyContent:'flex-end'
},
plus:{
width:60,
height:60,
borderWidth:1,
borderColor:'black',
textAlign:'right',
borderRadius:'15',
textAlign: 'center',
justifyContent: 'center',
fontSize:30
}
});
export default AddTask;
app.js
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View,Button, Alert,Input } from 'react-native';
import Task from './components/Task';
import AddTask from './components/AddTask';
export default function App() {
return (
<View style={styles.container}>
<View style = {styles.taskWrapper}>
<Text style={styles.header}>Today's Tasks</Text>
</View>
<View style={styles.tasks}>
<Task></Task>
<Task></Task>
</View>
<View>
<AddTask></AddTask>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#E8EAED',
},
taskWrapper:{
paddingTop:80,
paddingHorizontal:20
},
header:{
fontSize:24,
fontWeight:'bold'
},
tasks:{
},
});
You should use KeyboardAvoidingView in your app component so that whenever keyboard gets activated then the component of App gets pushed.

Problem with lining up contents: react native

I'm currently having a problem with the clickable size of a reusable button which includes an icon and text. When I run this code it seems like the entire row becomes clickable when I only want the icon and text to become clickable. Does anyone know how to solve this problem? Thanks
App.js
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';
import IconTextButton from './components/iconTextButton';
export default function App() {
return (
<View style={styles.container}>
<Text style={{marginTop: 100}}>My First React App! Sike </Text>
<IconTextButton iconFont="ionicons" iconName="pencil" iconSize={25} text="Add Items"/>
</View>
);
}
const styles = StyleSheet.create({
container: {
backgroundColor: 'powderblue',
},
});
iconTextButton.js
import React from 'react';
import { StyleSheet, TouchableOpacity, Text, View } from 'react-native';
import Ionicon from 'react-native-vector-icons/Ionicons';
export default function IconTextButton({ iconFont, iconName, iconSize, text, onPress }) {
const getIconFont = (iconFont) => {
switch (iconFont) {
case "ionicons":
return Ionicon;
}
};
const FontIcon = getIconFont(iconFont);
return (
<TouchableOpacity onPress={onPress} style={styles(iconSize).container>
<FontIcon name={iconName} size={iconSize} style={styles(iconSize).buttonIcon}>
<Text style={styles(iconSize).buttonText}>{text}</Text>
</FontIcon>
</TouchableOpacity>
)
}
const styles = (size) => StyleSheet.create({
container: {
backgroundColor: 'pink',
},
buttonIcon: {
backgroundColor: 'yellow',
width: size,
},
buttonText: {
backgroundColor: 'green'
},
})
Along with the code I've tried, I've also tried to keep and as seperate contents whilst adding a flexDirection: 'row' inside styles.container. This keeps the contents in the same line but it still makes the whole row clickable. I've also tried putting everything in a and moving the styles.container to the component and adding a height: size into styles.container. This makes the clickable component limited however, the component is hidden underneath due to the restricted height. I have also tried simply just using instead of making a reusable const that its an input. The same thing applies.
You can wrap your Icon and Text Component in a View component and then wrap it inside a TouchableOpacity Component
Try this or do something like this :
import React from 'react';
import { StyleSheet, TouchableOpacity, Text, View } from 'react-native';
import Ionicon from 'react-native-vector-icons/Ionicons';
export default function IconTextButton({ iconFont, iconName, iconSize, text, onPress }) {
const getIconFont = (iconFont) => {
switch (iconFont) {
case "ionicons":
return Ionicon;
}
};
const FontIcon = getIconFont(iconFont);
return (
<TouchableOpacity onPress={onPress} style={styles(iconSize).container}>
<View style={styles(iconSize).iconTextContainer}>
<FontIcon name={iconName} size={iconSize} style={styles(iconSize).buttonIcon} />
<Text style={styles(iconSize).buttonText}>{text}</Text>
</View>
</TouchableOpacity>
)
}
const styles = (size) => StyleSheet.create({
container: {
backgroundColor: 'pink',
},
iconTextContainer: {
flexDirection: 'row',
alignItems: 'center',
},
buttonIcon: {
backgroundColor: 'yellow',
width: size,
},
buttonText: {
backgroundColor: 'green'
},
})

MapView blocks input from keyboard

I am creating a map application with two simple components: a search bar, using react-native-paper and a map, using react-native-maps. By now, only the UI is implemented.
When placing only the search bar, everything works fine. I am able to type my search query and the keyboard pops up when I click on the bar:
import { StatusBar } from 'expo-status-bar';
import * as React from 'react';
import MapView, { Marker } from 'react-native-maps';
import { StyleSheet, View, Dimensions, PermissionsAndroid } from 'react-native';
import {
Provider as PaperProvider,
DarkTheme,
Drawer,
DefaultTheme,
BottomNavigation,
Text,
Appbar,
Theme,
TextInput,
Searchbar,
} from 'react-native-paper';
const styles=StyleSheet.create({
searchBar:{
width: '90%',
position: 'absolute',
top: '7%',
alignSelf: 'center',
}
})
const MyComponent = () => {
const [searchQuery, setSearchQuery] = React.useState('');
const onChangeSearch = query => setSearchQuery(query);
return (
<View style={{width: "100%", height: "100%"}}>
<Searchbar style={styles.searchBar}
placeholder="Search"
onChangeText={onChangeSearch}
value={searchQuery}
/>
</View>
);
};
export default MyComponent;
After adding the map, nothing happens when clicking the search box. If I type something on my physical keyboard, the input seems to be captured as the icon displays an animation, but nothing else happens.
import * as React from 'react';
import MapView, { Marker } from 'react-native-maps';
import { StyleSheet, View, Dimensions, PermissionsAndroid } from 'react-native';
import {
Provider as PaperProvider,
DarkTheme,
Drawer,
DefaultTheme,
BottomNavigation,
Text,
Appbar,
Theme,
TextInput,
Searchbar,
} from 'react-native-paper';
const styles=StyleSheet.create({
searchBar:{
width: '90%',
position: 'absolute',
top: '7%',
alignSelf: 'center',
}
})
const MyComponent = () => {
const [searchQuery, setSearchQuery] = React.useState('');
const { height, width } = Dimensions.get( 'window' );
const onChangeSearch = query => setSearchQuery(query);
return (
<View style={{width: "100%", height: "100%"}}>
<Searchbar style={styles.searchBar}
placeholder="Search"
onChangeText={onChangeSearch}
value={searchQuery}
/>
<MapView
style={{flex: 1}}
showsUserLocation={true}
showsMyLocationButton={true}
//onMapReady={_onMapReady}
region={{
latitude: -8.327352784611014,
longitude: -36.14413540428909,
latitudeDelta: 55.5,
longitudeDelta: 55.5 * (width / height),
}}></MapView>
</View>
);
};
export default MyComponent;
Any help is appreciated! This is my first react project.
have you tried messing around with zIndex?
maybe adding zIndex: 10 to the text input style
You have to change the order of TextInput and Mapview as you can find in their readme file: https://github.com/react-native-maps/react-native-maps#inputs-dont-focus
Bad:
<View>
<TextInput/>
<MapView/>
</View>
Good:
<View>
<MapView/>
<TextInput/>
</View>

Can I pass an array to a React Native ScrollView?

I'm trying to create a scrollable view using React Native's ScrollView with code below
import React from 'react';
import { Image, ScrollView, Text, StyleSheet, View, Dimensions } from 'react-native';
const styles = StyleSheet.create({
scrollView: {
height: '100%',
width: '100%',
flexDirection: 'column',
},
item: {
height: '20%',
width: '100%',
},
});
const data = [];
for (let i = 0; i < 30; i++) {
const datum = (
<View style={styles.item}>
<Text style={{ fontSize: 30 }}>{i.toString()}</Text>
</View>
);
data.push(datum);
}
const App = () => (
<ScrollView style={styles.scrollView}>
{data}
</ScrollView>
);
export default App;
Snack URL: https://snack.expo.io/rp6!W!HZm
When I run this code in Snack, seems like I cannot scroll down to the second page. I've checked the official documentation of ScrollView and it is passing ReactElement individually into the view.
RN official doc: https://reactnative.dev/docs/using-a-scrollview
Does this mean I cannot pass an array of elements as the children of a ScrollView? Is there anything I'm missing here?
This should do exactly what you're asking for!
The main thing happening here is the data mapping in the line
{data.map((item, index) => {
return (<View/>)
}}
where you are defining what is inside the scrollview... also your styling was a tad off so I touched it up.
Hope this helps!
import React from 'react';
import { ScrollView, Text, StyleSheet, View, Dimensions, SafeAreaView, TouchableOpacity } from 'react-native';
const { height } = Dimensions.get('screen');
function App() {
const data = [];
for (let i = 0; i < 30; i++) {
data.push('arbitrary datam #' + (i + 1));
}
return (
<SafeAreaView style={{ flex: 1 }}>
<ScrollView style={styles.scrollView}>
{data.map((item, index) => {
return (
<View key={index} style={styles.item}>
<Text style={{ fontSize: 30 }}>{item}</Text>
</View>
);
})}
</ScrollView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
scrollView: {
height: height,
},
item: {
height: height * 0.2,
width: '100%',
},
});
export default App;
Use flat list:
import React, {Component} from 'react';
import{AsyncStorage, View, ScrollView, FlatList} from 'react-native';
import {Text, List} from 'native-base';
class Notes extends Component {
constructor(props) {
super(props);
this.state = {
data: []
}
}
render () {
return (
<ScrollView>
<View style={{margin: 5, marginTop: 5}}>
<List>
<FlatList
data={this.state.data}
renderItem={({item, index}) =>
<View style={styles.item}>
<Text style={{ fontSize: 30 }}>{item.toString()}</Text>
</View>
}
keyExtractor={(item, index) => index.toString()}
/>
</List>
</View>
</ScrollView>
)
}
}
export default Notes;

React Native bottom modal with horizontal scroll

I'm trying to get a modal working to look like the picture below. I've tried various modal and actionsheet solutions but can't quite get it right. Does anyone know if a solution exists that can provide a similar result? Thanks]1
I have been using an action sheet from a library (pic below) but it cannot be customized to scroll horizontally and use custom buttons. I also have not yet attempted in creating my own, I first wanted to know if anyone knows of a component which will yield the same result.
Regular action sheet on iOS
Here is a simple working example as per your requirement. I am using react-native-modal for Modal component.
import React, { Component } from 'react'
import {
StyleSheet,
Text,
View,
TouchableOpacity,
ScrollView
} from 'react-native'
import Modal from 'react-native-modal'
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
visible: false
}
}
showModal = () => this.setState({visible: true})
hideModal = () => this.setState({visible: false})
render() {
return (
<View style={{flex: 1}}>
<TouchableOpacity
onPress={this.showModal}
style={{alignSelf: 'center', marginTop: 50, backgroundColor: 'grey'}}
>
<Text>Touch Me</Text>
</TouchableOpacity>
<Modal
style={styles.modal}
isVisible={this.state.visible}
onBackdropPress={this.hideModal}
>
<ScrollView
horizontal={true}
>
{/* place your buttons here */}
<Text> Very Very Long String </Text>
</ScrollView>
</Modal>
</View>
)
}
}
const styles = StyleSheet.create({
modal: {
margin: 0,
backgroundColor: 'white',
height: 100,
flex:0 ,
bottom: 0,
position: 'absolute',
width: '100%'
}
})