So I originally needed to pass states while navigating from a screen to another because I thought that would be enough to update a button as well as the screen iteself. However, the button that controlled the states is not being updated with the screen.
In the demo provided below(I included the code here as well) you can see that when navigating from Screen3, the state updates so that the red screen renders but the button at the top does not update as well.
How can I update the button along with the screen being updated? I need to go from screen3 to the red screen while the button at the top shows we are on the red screen as well.
Here is the demo as well as the code below. Please keep in mind you must run the snack on IOS or android and you need to be running Expo Version 42(located in the bottom right of the screen)
Thank you for any insight at all! I appreciate it more than you know.
Home.js
import Slider from './components/slider'
const Home = ({ route }) => {
const [isVisile, setIsVisible] = React.useState(true);
const [whichComponentToShow, setComponentToShow] = React.useState("Screen1");
React.useEffect(() => {
if(route.params && route.params.componentToShow) {
setComponentToShow(route.params.componentToShow);
}
}, [route.params]);
const goToMap = () => {
setComponentToShow("Screen2");
}
const goToList = () => {
setComponentToShow("Screen1");
}
return(
<View style={{backgroundColor: '#d1cfcf' ,flex: 1}}>
{whichComponentToShow === 'Screen1' && <ListHome />}
{whichComponentToShow === 'Screen2' && <MapHome />}
<View style={{position: 'absolute', top: 0, left: 0, right: 1}}>
<Slider
renderMap={goToMap}
renderList={goToList}
/>
</View>
</View>
);
}
Screen3.js
const Screen3 = (props) => {
const navigation = useNavigation();
const onPress = () => {
navigation.navigate('Home', {
screen: 'Home',
params: {
componentToShow: 'Screen2'
}
});
}
return (
<View
style={{
flex: 1,
backgroundColor: 'white',
justifyContent: 'center',
alignItems: 'center',
}}>
<TouchableOpacity onPress={onPress}>
<Text style={{ color: 'black', fontSize: 25 }}>
Navigate to home and change to map screen
</Text>
</TouchableOpacity>
</View>
);
};
Finally Slider.js
const Slider = (props) => {
const [active, setActive] = useState(false)
let transformX = useRef(new Animated.Value(0)).current;
useEffect(() => {
if (active) {
Animated.timing(transformX, {
toValue: 1,
duration: 300,
useNativeDriver: true
}).start()
} else {
Animated.timing(transformX, {
toValue: 0,
duration: 300,
useNativeDriver: true
}).start()
}
}, [active]);
const rotationX = transformX.interpolate({
inputRange: [0, 1],
outputRange: [2, Dimensions.get('screen').width / 4]
})
return (
code for animation
)
CodePudding user response:
Your Slider
component needs to listen to screen focus with useFocusEffect
and react accordingly. I added new props active
to detect if the map screen is active.
Slider.js
import * as React from 'react';
import { useState, useEffect, useRef } from 'react'
import { View, Text, StyleSheet, Animated, TouchableOpacity, SafeAreaView, Dimensions, } from 'react-native';
import {
scale,
verticalScale,
moderateScale,
ScaledSheet,
} from 'react-native-size-matters';
import { useFocusEffect } from '@react-navigation/native';
const Slider = (props) => {
const [active, setActive] = useState(false)
let transformX = useRef(new Animated.Value(0)).current;
useFocusEffect( React.useCallback(()=>{
setActive(Boolean(props.active))
console.log()
},[props.active]))
useEffect(() => {
if (active) {
Animated.timing(transformX, {
toValue: 1,
duration: 300,
useNativeDriver: true
}).start()
} else {
Animated.timing(transformX, {
toValue: 0,
duration: 300,
useNativeDriver: true
}).start()
}
}, [active]);
const rotationX = transformX.interpolate({
inputRange: [0, 1],
outputRange: [2, Dimensions.get('screen').width / 4]
})
return (
<SafeAreaView style={{
alignItems: 'center',
backgroundColor:'transparent'
}}>
<View style={{
flexDirection: 'row',
position: 'relative',
height: 45,
width: 240,
borderRadius: 10,
backgroundColor: 'white',
marginHorizontal: 5
}}>
<Animated.View
style={{
position: 'absolute',
height: 45 - 2*2,
top: 2,
bottom: 2,
borderRadius: 10,
width: Dimensions
.get('screen').width / 3 - 3.5 ,
transform: [
{
translateX: rotationX
}
],
backgroundColor: '#d1cfcf',
}}
>
</Animated.View>
<TouchableOpacity style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}} onPress={() => {setActive(false); props.renderList() }}>
<Text>
List
</Text>
</TouchableOpacity>
<TouchableOpacity style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}} onPress={() => {setActive(true); props.renderMap() }}>
<Text>
Map
</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
);
}
export default Slider
I update Slider Component in Home.js
as below.
<Slider
renderMap={goToMap}
renderList={goToList}
active={route.params && route.params.componentToShow==='Screen2'}
/>
Check full working snack: https://snack.expo.dev/@emmbyiringiro/283f93