Changed from react native class to function and it doesnt work 100% - react-native

I am trying to change a class into a function. This is mainly because if I can get it working, I want to use it for learning different animations, I have had some success but not 100%. Originally it displayed an icon that when clicked it spun it one way and then when clicked again it spun the other way. What I have tried to do it get rid of the icon and replace it with an image. It works when clicked once but then does nothing.
I am struggling with toggled aspect of it and setting the state I think because I cant seem to set it up properly in a function.
I have tried several things but this is the best I can get. If I show the original code and then what I have managed to change, maybe someone can point me in the right direction as to what I am doing wrong.
All I want is the image to display and then when clicked spins right and then if clicked again it spins left.
I am doing this so I can mess around with the settings and hopefully learn animation a bit better.
Any help would be greatly appreciated.
The original code :
import React from 'react';
import { View, StyleSheet, Animated, Image, TouchableOpacity } from 'react-native';
import { Ionicons } from '#expo/vector-icons';
const TabIcon = ({
onPress,
menuToggled
}) => {
const logoStyles = [styles.logoStyle];
if (menuToggled !== null) {
const animation = new Animated.Value(menuToggled ? 0 : 1);
Animated.timing(animation, {
toValue: menuToggled ? 1 : 0,
duration: 500,
useNativeDriver: true
}).start();
const rotateInterpolate = animation.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '360deg']
});
const animatedStyles = { transform: [{ rotate: rotateInterpolate }] };
logoStyles.push(animatedStyles);
}
return (
<TouchableOpacity
style={styles.tabStyle}
onPress={onPress}
>
<Animated.View style={logoStyles}>
<Animated.Image
style={styles.tinyLogo}
source={{
uri: 'https://reactnative.dev/img/tiny_logo.png',
}}
/></Animated.View>
</TouchableOpacity>
);
};
export default class App extends React.Component {
state = {
menuToggled: null
}
toggleMenu = () => {
this.setState(prevState => {
return { menuToggled: !prevState.menuToggled };
});
}
render () {
return (
<View style={styles.container}>
<TabIcon
onPress={this.toggleMenu}
menuToggled={this.state.menuToggled}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'white'
},
tinyLogo: {
width: 150,
height: 150,
borderRadius: 100,
margin: 8,
},
});
and what I have changed so far :
import React, { useRef, useState } from "react";
import { View, StyleSheet, Animated, Image, TouchableOpacity, Easing } from 'react-native';
import Constants from 'expo-constants';
const App = () => {
const spinValue = useRef(new Animated.Value(0)).current;
const [menuToggled, setMenuToggled] = useState([null]);
toggleMenu = () => {
setMenuToggled(menuToggled === "null" ? "menuToggled" : "null");
}
const Spinner = ({
onPress,
menuToggled
}) => {
const logoStyles = [styles.logoStyle];
const animation = new Animated.Value(0);
const go = () => {
Animated.timing(animation, {
toValue: 1,
duration: 1500,
easing: Easing.elastic(1),
useNativeDriver: true
}).start();
}
const rotateInterpolate = animation.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '360deg']
});
const animatedStyles = { transform: [{ rotate: rotateInterpolate }] };
logoStyles.push(animatedStyles);
return (
<TouchableOpacity
onPress={go}
>
<Animated.View style={logoStyles}>
<Animated.Image
style={styles.tinyLogo}
source={{
uri: 'https://reactnative.dev/img/tiny_logo.png',
}}
/></Animated.View>
</TouchableOpacity>
);
};
return (
<View style={styles.container}>
<Spinner
onPress={toggleMenu}
menuToggled={menuToggled}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'white'
},
tinyLogo: {
width: 150,
height: 150,
borderRadius: 100,
margin: 8,
},
});
export default App;

There are a few issues. You first had menuToggled initialized to [null] when it should have been null. You also had forgotten to use onPress in TabIcon. The most noteworthy thing was wrapping TabIcon in a useCallback to prevent it from being recreated all the time. Expo snack:
import React, { useRef, useState, useCallback } from 'react';
import {
View,
StyleSheet,
Animated,
Image,
TouchableOpacity,
} from 'react-native';
import Constants from 'expo-constants';
const App = () => {
const spinValue = useRef(new Animated.Value(0)).current;
const [menuToggled, setMenuToggled] = useState(null);
const TabIcon = useCallback(({ onPress, menuToggled }) => {
const logoStyles = [styles.logoStyle];
// initialized base on menuToggled
// if not done then it will take an additional button press to trigger
// the animation
const animation = useRef(new Animated.Value(menuToggled ? 0 : 1)).current;
const startAnimation = () => {
Animated.timing(animation, {
toValue: menuToggled ? 1 :0,
duration: 500,
useNativeDriver: true,
}).start();
};
const rotateInterpolate = animation.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '360deg'],
});
const animatedStyles = { transform: [{ rotate: rotateInterpolate }] };
logoStyles.push(animatedStyles);
return (
<TouchableOpacity
onPress={() => {
startAnimation();
onPress?.();
}}>
<Animated.View style={logoStyles}>
<Animated.Image
style={styles.tinyLogo}
source={{
uri: 'https://reactnative.dev/img/tiny_logo.png',
}}
/>
</Animated.View>
</TouchableOpacity>
);
},[]);
return (
<View style={styles.container}>
<TabIcon
onPress={() => setMenuToggled((prev) => !prev)}
menuToggled={menuToggled}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'white',
},
tinyLogo: {
width: 150,
height: 150,
borderRadius: 100,
margin: 8,
},
});
export default App;

Related

react native reanimated three items but one bigger as the neighbor

I want to make a flatlist with three items and the selected/current Index item should be bigger as the two items next to.
Current Code:
const translateX = useSharedValue(0);
const scrollHandler = useAnimatedScrollHandler({
onScroll: (e) => {
translateX.value = e.contentOffset.x;
}
})
const animatedStyle = useAnimatedStyle(() => {
const scale = interpolate(translateX.value, [width / 3, 0, width / 3], [0.2, 1, 0.2], Extrapolate.CLAMP);
return {
transform: [{
scale
}]
}
}, []);
const renderI = ({ item }) => (
<Animated.View style={[animatedStyle]}>
<ProductCardAuto
{...item}
onPressProduct={() => handleNavigateToProduct(item)}
onPressReviews={handleOpenModalReviews}
/>
</Animated.View>
)
<Animated.FlatList
data={mockProducts}
renderItem={renderI}
keyExtractor={(item) => item.id}
snapToAlignment="start"
decelerationRate={"normal"}
onScroll={scrollHandler}
horizontal
snapToInterval={120}
/>
I am very thankful for your help. Idk what I am doing wrong. Maybe you can tell me what is wrong with it. it does not work its scale all items to 0.2 if I scroll
Even if the question has been already answered, I would suggest another approach.
What worked for me is react-native-reanimated-carousel, which not only that is very easy to use and very customizable, but is also using react-native-reanimated and that means native performance and precise animations because it runs the animations on the UI thread rather than the JS thread.
EDIT: I noticed that you're actually looking for a reanimated answer, which is great!
Based on the library I showed you, I believe you're looking for a parallax horizontal.
Here's a link to the example: https://github.com/dohooo/react-native-reanimated-carousel/blob/main/exampleExpo/src/pages/parallax/index.tsx
kindof tried to make it acc to what you needed.
You can check this expo : https://snack.expo.dev/d_myr1HdyN
import React,{useState,useEffect,useRef,useCallback} from 'react';
import { Text, View, StyleSheet ,Animated,FlatList,Dimensions,Easing } from 'react-native';
import Constants from 'expo-constants';
// You can import from local files
import AssetExample from './components/AssetExample';
// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';
const data = ["hey there","indian","mango","whatsup","arsenal","jojoba"]
const screenWidth = Dimensions.get("window").width;
const EachItem = (props) => {
const {text = "",index=0,currentView={}} = props || {}
const {visible = false, index:visibleIndex = 0} = currentView;
console.log(visible,visibleIndex,"wuhyyyyy")
const animRef = useRef(new Animated.Value(0)).current
const startAnimation = useCallback(() => {
Animated.timing(animRef,{
toValue:1,
duration:1000,
useNativeDriver:true,
easing:Easing.ease,
}).start()
},[animRef])
const stopAnim = useCallback(() => {
Animated.timing(animRef,{
toValue:0,
duration:1000,
useNativeDriver:true,
easing:Easing.ease,
}).start()
},[animRef])
useEffect(() => {
if(visible === true && visibleIndex===index ){
startAnimation()
}
if(visible === false ){
setTimeout(() =>stopAnim(),1000)
}
},[startAnimation,visible,visibleIndex,index,stopAnim])
const scaleInter = animRef.interpolate({inputRange:[0,1],outputRange:[1,1.5]})
return(
<Animated.View style={{marginHorizontal:20 ,height:100,
backgroundColor:'rgba(102,116,255,0.6)',
width:screenWidth/3,
alignItems:'center',
justifyContent:'center',
transform:[{
scale:scaleInter
}]
}} >
<Text>{text}</Text>
</Animated.View>
)
}
export default function App() {
const [currentView,setCurrentView] = useState({visible:false,index:null})
const onViewRef = React.useRef((viewableItems) => {
console.log(viewableItems?.viewableItems,"viewableItems")
if(viewableItems?.viewableItems.length === 2){
setCurrentView({visible:false,index:null})
}
if(viewableItems?.viewableItems.length === 1){
const currentItemIndex = viewableItems?.viewableItems[0]?.index
setCurrentView({visible:true,index:currentItemIndex})
}
});
const viewConfigRef = React.useRef({ viewAreaCoveragePercentThreshold: 30 });
const eachItem = ({item,index}) => {
return <EachItem text={item} currentView={currentView} index={index} />
}
return (
<View style={styles.container}>
<Animated.FlatList
data={data}
style={{flex:1}}
contentContainerStyle={{paddingTop:100}}
horizontal={true}
onViewableItemsChanged={onViewRef.current}
viewabilityConfig={viewConfigRef.current}
renderItem={eachItem}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
// justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
// alignItems:'center'
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
});
Hope it helps. feel free for doubts

React native flatlist inverted onscrollbegin runs every time I scrol

I want to use onScrollBegin on my flatlist. But everytime I make scroll the function runs. I only want to run this function when I am at the top, not everytime I scroll.
import * as React from 'react';
import { StyleSheet, Text, View, Pressable, Image, Dimensions, Platform, FlatList, TextInput } from 'react-native';
import { messages } from '../utils/mockChat';
import { useDispatch, useSelector } from 'react-redux';
import moment from 'moment';
import Modal from 'react-native-modalbox';
import { openModalImage } from '../redux/slice/chat/chatSlice';
const { width, height } = Dimensions.get('screen');
function propsEqual(prevProp, nextProp) {
if(prevProp.id === nextProp.id) {
return true;
}
}
const Item = React.memo(({ global_user_id, id, type, render, allDates, name, user_id, reciever, text, images, video, sending, pending, read, date }) => {
const dateNum = moment(date).format('DD-MM-YYYY');
return (
<View style={s.item}>
<View style={s.itemContainer}>
<View style={global_user_id === user_id ? s.ownerText : s.reciever_text}>
<Text style={s.text}>{ text }</Text>
</View>
</View>
</View>
)
}, propsEqual);
const userState = state => state.user.userID;
const modalState = state => state.chatSlice.modalImage;
const Chat = ({ route, navigation }) => {
const { image } = route.params;
const dispatch = useDispatch();
const modalSec = useSelector(modalState);
const userID = useSelector(userState);
const [message, setMessage] = React.useState(generateItems(messages));
const modalR = React.useRef(null);
const timerCloseModal = React.useRef(null);
React.useEffect(() => {
modalSec && modalR.current.open();
}, [modalSec]);
const dates = new Set();
function renderDate(date) {
dates.add(moment(date).format('DD-MM-YYYY'));
return (
<Text style={{color: '#333', fontSize: 12}}>{moment(date).format('DD-MM-YYYY')}</Text>
)
}
const showFooter = () => {
return (
<View style={s.footerContainer}>
<TextInput style={{height: 50, width: '100%', padding: 20}} />
</View>
)
};
const rowRenderer = ({ item }) => {
return (
<Item
item={item}
id={item.id}
allDates={dates}
render={(date) => renderDate(date)}
global_user_id={userID}
name={item.name}
user_id={item.user_id}
reciever={item.reciever}
text={item.text}
images={item.images}
video={item.video}
sending={item.sending}
pending={item.pending}
read={item.read}
type={item.type}
date={item.date} />
)
};
const closeModalImage = React.useCallback(() => {
dispatch(openModalImage());
}, [dispatch, modalR]);
return (
<View style={s.container}>
<FlatList
data={message}
keyExtractor={i => i.id.toString()}
renderItem={rowRenderer}
initialNumToRender={10}
onScrollBeginDrag={() => {
console.log('s');
// setMessage(items);
}}
extraData={message}
ListHeaderComponent={showFooter}
inverted
/>
</View>
)
};
const s = StyleSheet.create({
container: {
flex: 1
},
modal: {
justifyContent: 'center',
alignItems: 'center',
width: 300,
height: 300,
borderRadius: 200,
backgroundColor: 'transparent',
maxHeight: 500,
},
item: {
backgroundColor: 'red',
height: 250,
width: width * 0.8,
marginVertical: 12
},
ownerText: {
alignSelf: 'flex-end',
backgroundColor: 'blue'
},
reciever_text: {
alignSelf: 'flex-start'
}
});
export default Chat;
How can I fix it, that I can only scroll if I am on the top? I use inverted so its hard for me, to know where is the top position. I am very thankful for your help
Make use of the onEndReached prop.
The onEndReached function calls every time you reach the end of a list.
official doc

Error while animating rotateX in react native

I am trying to rotate an icon on press of a button in my react native application.
But I am getting this error:
Error while updating property 'transform' of a view managed by:
RCTView
This is the Icon itself:
<TouchableOpacity
style={[
styles.expandButton,
{transform: [{rotateX: toString(expandIconAngle) + 'deg'}]},
]}
onPress={() => {
rotateIcon();
}}>
<Icon name="expand-less" color="#ffffff" size={28} />
</TouchableOpacity>
This is the function which is responsible for rotating the icon:
const expandIconAngle = useRef(new Animated.Value(0)).current;
function rotateIcon() {
Animated.timing(expandIconAngle, {
toValue: 180,
duration: 300,
easing: Easing.linear,
}).start();
}
Where am I going wrong?
use interpolate and Animated.Image :
import React, { useRef } from "react";
import { Animated, Text, View, StyleSheet, Button, SafeAreaView,Easing,TouchableOpacity } from "react-native";
const App = () => {
// fadeAnim will be used as the value for opacity. Initial Value: 0
const angle = useRef(new Animated.Value(0)).current;
const fadeOut = () => {
// Will change fadeAnim value to 0 in 3 seconds
Animated.timing(
angle,
{
toValue: 1,
duration: 3000,
easing: Easing.linear, // Easing is an additional import from react-native
useNativeDriver: true // To make use of native driver for performance
}
).start()
};
const spin =angle.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '360deg']
})
return (
<SafeAreaView style={styles.container}>
<Animated.Image
style={{transform: [{rotateX: spin}] }}
source={require('#expo/snack-static/react-native-logo.png')} />
<TouchableOpacity onPress={fadeOut} style={styles.buttonRow}>
<Text>Button</Text>
</TouchableOpacity>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center"
},
buttonRow: {
flexBasis: 100,
justifyContent: "space-evenly",
marginVertical: 16
}
});
export default App;
LIVE example - https://snack.expo.dev/TP-fQExXT

Problems with automatic image carousel when data is dynamic from an api using react native

I am implementing an image carousel which has an automatic rotation. When I implement it with static data (for example: creating a constant with an array) it works just the way I want it to.
However when I am getting the data from an api using axios, the carrosuel has a wrong behavior. The wrong behavior is as follows:
Swipe to the second image on the carousel and before moving on to the third image, go back to the first image and then go to the third image, then go to the fourth image, go back to the first image, and then go to the first image. fourth, this behavior is repeated x times.
So I think the problem is when I use axios. I attach the code of the classes that intervene in the problem that I am currently presenting.
I am using react native 0.62 with hooks and axios
HomeScreen.js
import React, { useEffect, useState } from "react";
import { View } from "react-native";
import CategoriesScreen from "./Categories/CategoriesScreen";
import { ScrollView } from "react-native-gesture-handler";
import Carousel from "./Banner/BannerOficial";
import { axiosClient } from "../../config/axios";
export default function HomeScreen({ navigation }) {
const [banners, setBanners] = useState([]);
useEffect(() => {
getBannersAPI();
}, []);
function getBannersAPI(){
axiosClient
.get("/service/banner_available")
.then(async function (response) {
setBanners(response.data);
})
.catch(function (error) {
console.log("Error cargando los banners: ", error);
});
}
return (
<View style={{ flex: 1 }}>
<ScrollView>
<Carousel data={banners} />
<CategoriesScreen navigation={navigation} />
</ScrollView>
</View>
);
}
Carousel.js
import React, { useState, useEffect } from 'react'
import { View, Text, StyleSheet, Dimensions, FlatList, Animated } from 'react-native'
import CarouselItem from './BannerItem'
const { width, heigth } = Dimensions.get('window')
let flatList
function infiniteScroll(dataList){
const numberOfData = dataList.length
let scrollValue = 0, scrolled = 0
setInterval(function() {
scrolled ++
if(scrolled < numberOfData)
scrollValue = scrollValue + width
else{
scrollValue = 0
scrolled = 0
}
this.flatList.scrollToOffset({ animated: true, offset: scrollValue})
}, 3000)
}
const Carousel = ({ data }) => {
const scrollX = new Animated.Value(0)
let position = Animated.divide(scrollX, width)
const [dataList, setDataList] = useState(data)
useEffect(()=> {
setDataList(data)
infiniteScroll(dataList)
})
if (data && data.length) {
return (
<View>
<FlatList data={data}
ref = {(flatList) => {this.flatList = flatList}}
keyExtractor={(item, index) => 'key' + index}
horizontal
pagingEnabled
scrollEnabled
snapToAlignment="center"
scrollEventThrottle={16}
decelerationRate={"fast"}
showsHorizontalScrollIndicator={false}
renderItem={({ item }) => {
return <CarouselItem item={item} />
}}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { x: scrollX } } }]
)}
/>
<View style={styles.dotView}>
{data.map((_, i) => {
let opacity = position.interpolate({
inputRange: [i - 1, i, i + 1],
outputRange: [0.3, 1, 0.3],
extrapolate: 'clamp'
})
return (
<Animated.View
key={i}
style={{ opacity, height: 10, width: 10, backgroundColor: '#595959', margin: 8, borderRadius: 5 }}
/>
)
})}
</View>
</View>
)
}
console.log('Please provide Images')
return null
}
const styles = StyleSheet.create({
dotView: { flexDirection: 'row', justifyContent: 'center'}
})
export default Carousel
CarouselItem.js
import React from "react";
import { View, StyleSheet, Text, Image, Dimensions} from 'react-native';
const { width, height} = Dimensions.get('window')
const CarouselItem = ({item}) => {
return(
<View style={styles.cardView}>
<Image style={styles.image} source = {{ uri: item.imagePath}}/>
</View>
)
}
const styles = StyleSheet.create({
cardView:{
flex:1,
width: width -20,
height: height / 7,
backgroundColor: "white",
margin: 10,
borderRadius: 10,
shadowColor: "#000",
shadowOffset: {width: 0.5, height: 0.5},
shadowOpacity: 0.5,
shadowRadius: 3,
elevation: 5,
},
image: {
width: width-20,
height: height / 3,
borderRadius: 10
}
})
export default CarouselItem

MultipleScreens(like a stack) on top of one another in react native

In react native, can we achieve a UI where there are multiple screens stacked on top of each other with each screen stacking on top of the other on click of a button.
Let's say, there is Screen A. Upon click of a button, Screen B is placed as a stack on Screen A and screen A is still partly visible as Screen B doesn't occupy the entire screen layout. Similarly, Screen C adds up to the stack upon the click of a button in Screen B and screen B is still visible along with screen A in the background. All these come with a side animation from the left (similar to navigation drawer). With a common button, all the above screens can be popped out from the stack and the previous screen comes to the top with a side animation again, this time to the right.
I wanted to understand if the above is possible in react native? If yes, how I can achieve it? I wish I can show the design but I cannot do that atm.
With react-native-vertical-view-pager you can do it.
install with:
npm install --save react-native-vertical-view-pager
or with yarn (if you use yarn):
yarn add react-native-vertical-view-pager
and use as follow:
import React from 'react';
import { StyleSheet, Text, View, Dimensions } from 'react-native';
import VerticalViewPager from 'react-native-vertical-view-pager';
const { width, height } = Dimensions.get('window');
export default class App extends React.Component {
render() {
return (
<VerticalViewPager
showsVerticalScrollIndicator={false}>
<View style={[styles.page_container, {backgroundColor: 'pink'}]}>
<Text>Page1: Open up App.js to start working on your app!</Text>
</View>
<View style={[styles.page_container, {backgroundColor: 'olive'}]}>
<Text>Page2: Changes you make will automatically reload.</Text>
</View>
<View style={[styles.page_container, {backgroundColor: 'lightblue'}]}>
<Text>Page3: Shake your phone to open the developer menu.</Text>
</View>
</VerticalViewPager>
);
}
}
const styles = StyleSheet.create({
page_container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
width,
height
}
});
with your screens on the place of the views.
I could achieve this functionality using a very cool library named 'react-native-modalfy'.
import React, { PureComponent } from 'react'
import {
Easing,
Dimensions,
StatusBar,
StyleSheet,
Text,
View,
} from 'react-native'
import { ModalProvider, createModalStack } from 'react-native-modalfy'
import CardModal from './modals/CardModal'
import Button from './components/Button'
const { width } = Dimensions.get('screen')
const config = { ModalA: CardModal, ModalB: CardModal, ModalC: CardModal }
const defaultOptions = {
transitionOptions: animatedValue => ({
opacity: animatedValue.interpolate({
inputRange: [0, 1, 2],
outputRange: [0, 1, .9],
}),
transform: [
{
perspective: 2000
},
{
translateX: animatedValue.interpolate({
inputRange: [0, 1, 2],
outputRange: [-width / 2, 0, 25],
}),
},
{
scale: animatedValue.interpolate({
inputRange: [0, 1, 2],
outputRange: [1.2, 1, .9],
}),
},
],
}),
animateInConfig: {
easing: Easing.bezier(.42,-0.03,.27,.95),
duration: 450,
},
animateOutConfig: {
easing: Easing.bezier(.42,-0.03,.27,.95),
duration: 450,
},
}
const stack = createModalStack(config, defaultOptions)
class App extends PureComponent {
render() {
return (
<ModalProvider stack={stack}>
<View style={styles.container}>
<StatusBar animated hidden translucent />
<Text style={styles.title}>RNM</Text>
<Button label="Open ModalA" modalToOpen="ModalA" color="tomato" />
<Button label="Open ModalB" modalToOpen="ModalB" color="darkcyan" />
<Button label="Open ModalC" modalToOpen="ModalC" color="deeppink" />
</View>
</ModalProvider>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'indigo',
alignItems: 'center',
justifyContent: 'center'
},
title: {
color: 'white',
fontSize: 54,
fontWeight: 'bold',
marginBottom: 50,
},
})
export default App
import React, { PureComponent } from 'react'
import {
Button as ButtonModule,
Dimensions,
StyleSheet,
Text,
View,
} from 'react-native'
import Button from '../components/Button'
const { width: ww, height: wh } = Dimensions.get('screen')
class CardModal extends PureComponent {
componentDidMount() {
const { modal } = this.props
this.modalListenerID = modal.addListener('onAnimate', this._handleAnimation)
}
componentWillUnmount() {
this.modalListenerID?.remove()
}
_handleAnimation = animatedValue => {
const { currentModal } = this.props.modal
console.info(`${currentModal}:`, animatedValue)
}
render() {
const {
currentModal,
closeModal,
closeModals,
closeAllModals,
params: { color },
} = this.props.modal
return (
<View style={[styles.card]}>
<Text style={styles.title(color)}>{currentModal}</Text>
<Button label="Open ModalA" modalToOpen="ModalA" color="tomato" />
<Button label="Open ModalB" modalToOpen="ModalB" color="darkcyan" />
<Button label="Open ModalC" modalToOpen="ModalC" color="deeppink" />
<ButtonModule title="Close" onPress={closeModal} color="dodgerblue" />
<ButtonModule title={`Close all ${currentModal}`} onPress={() => closeModals(currentModal)} color="dodgerblue" />
<ButtonModule title="Close all modals" onPress={closeAllModals} color="red" />
</View>
)
}
}
const styles = StyleSheet.create({
title: color => ({
color,
fontSize: 48,
fontWeight: 'bold',
marginBottom: 50,
}),
card: {
marginRight : 90,
width: ww,
height: wh,
backgroundColor: 'cyan',
elevation: 0,
alignItems: 'center',
justifyContent: 'center',
borderRadius: 0,
},
})
export default CardModal
import React, { PureComponent } from 'react'
import { TouchableOpacity, StyleSheet, Text } from 'react-native'
import { withModal } from 'react-native-modalfy'
class Button extends PureComponent {
openModal = () => {
const { color, modalToOpen, modal } = this.props
modal.openModal(modalToOpen, { color })
}
render() {
const { color, label } = this.props
return (
<TouchableOpacity onPress={this.openModal} style={styles.button(color)}>
<Text style={styles.label}>{label}</Text>
</TouchableOpacity>
)
}
}
const styles = StyleSheet.create({
button: backgroundColor => ({
backgroundColor,
paddingHorizontal: 60,
paddingVertical: 21,
borderRadius: 21,
marginBottom: 30,
}),
label: {
fontSize: 16,
fontWeight: '800',
color: 'white',
textAlign: 'center',
},
})
export default withModal(Button)