react-native-switch
react-native-switch copied to clipboard
Switch not visually toggling in drawer navigator but state is changing
So in my Drawer.Navigator is a page called settings.js that manages state for my switch, SettingsComponent.jsx that uses Switch from 'react-native-switch'. The problem is that when I press the switch, it doesn't visually toggle, but according to console.log, the state is actually changing.
Before I implemented the state in settings.js, it used to be able to toggled.
I tried every trick in the book (I believe), using 'useDrawerStatus', 'useCallback', 'useEffect' to re-render, but nothing seems to want to make my switch visually move!
For more context, settings.js is a Drawer.Screen in my Drawer.Navigator and I believe this is to be the issue as I believe the switch is able to visually toggle if it were in my Stack.Navigator instead as previously, I have encountered the same problem but with the native 'Switch' component from 'react-native' and just by moving the component to my Stack.Screen, it ends up being able to visually toggle.
settings.js
import React, { useState, useCallback, useEffect } from 'react';
import { View, ScrollView, SafeAreaView } from 'react-native';
import { useNavigation, useFocusEffect } from '@react-navigation/native';
import SettingsComponent from '../myComponents/drawer/settings/SettingsComponent';
import { COLORS, icons, images, FONT, SIZES } from '../constants';
function Settings({navigation}) {
const [isBreakContinueEnabled, setBreakContinueEnabled] = useState(false);
const [isBreakSaveEnabled, setBreakSaveEnabled] = useState(false);
const [isNotificationEnabled, setNotificationEnabled] = useState(false);
const setBreakContinueEnabledMemoized = useCallback((value) => {
setBreakContinueEnabled(value);
}, []);
const setBreakSaveEnabledMemoized = useCallback((value) => {
setBreakSaveEnabled(value);
}, []);
const setNotificationEnabledMemoized = useCallback((value) => {
setNotificationEnabled(value);
}, []);
useEffect(() => {
}, [isBreakContinueEnabled, isBreakSaveEnabled, isNotificationEnabled]);
console.log({ isBreakContinueEnabled, isBreakSaveEnabled, isNotificationEnabled });
const breakContinue=[{title: 'Continue after break', subTitle:'Stopwatch starts once break ends'}];
const breakSave=[{title: 'Save break time', subTitle:'Save break time for later on continue'}];
const notificationToggle=[{title: 'Notifications', subTitle: 'Notification when break ends'}];
return (
<SafeAreaView style={{ flex: 1, backgroundColor: COLORS.grayBeige }}>
<ScrollView showsVerticalScrollIndicator={false}>
<View>
<SettingsComponent
settingsOptions={breakContinue}
isEnabled={isBreakContinueEnabled}
setIsEnabled={setBreakContinueEnabledMemoized}
/>
<SettingsComponent
settingsOptions={breakSave}
isEnabled={isBreakSaveEnabled}
setIsEnabled={setBreakSaveEnabledMemoized}
/>
<SettingsComponent
settingsOptions={notificationToggle}
isEnabled={isNotificationEnabled}
setIsEnabled={setNotificationEnabledMemoized}
/>
</View>
</ScrollView>
</SafeAreaView>
);
}
export default Settings;
SettingsComponent.jsx
import { useState } from 'react';
import { View, Text, SafeAreaView, ScrollView } from 'react-native';
import { TouchableOpacity } from 'react-native-gesture-handler';
import { Switch } from 'react-native-switch';
import { useDrawerStatus } from '@react-navigation/drawer';
import { COLORS, FONT, SIZES } from '../../../constants';
const SettingsComponent = ({settingsOptions, isEnabled, setIsEnabled}) => {
const isDrawerOpen = useDrawerStatus() === 'open';
const toggleSwitch = () => {
if (!isDrawerOpen){
setIsEnabled(previousState => !previousState);
}
}
return (
<SafeAreaView>
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'space-between' }}>
{settingsOptions.map(({title, subTitle }, index) =>
<TouchableOpacity key={title}>
<View style={{
paddingHorizontal: 20,
paddingTop: 20,
paddingBottom: 20,
}}>
<Text style={{fontFamily: FONT.medium, fontSize: SIZES.medium, color: COLORS.themeColor}}>{title}</Text>
{subTitle && <Text style={{fontFamily: FONT.regular, fontSize: SIZES.small, color: COLORS.lightThemeColor}}>{subTitle}</Text>}
</View>
</TouchableOpacity>
)}
<View
style={{
paddingHorizontal: 20,
paddingTop: 20,
paddingBottom: 20,
justifyContent: 'center',
}}
>
<Switch
value={isEnabled}
onValueChange={toggleSwitch}
disabled={false}
activeText={'On'}
inActiveText={'Off'}
circleSize={25}
barHeight={20}
circleBorderWidth={1}
circleBorderActiveColor={COLORS.themeColor}
circleBorderInactiveColor={'#c9beb1'}
backgroundActive={COLORS.themeColor}
backgroundInactive={'#c9beb1'}
circleActiveColor={COLORS.lightBeige}
circleInActiveColor={COLORS.lightBeige}
changeValueImmediately={true} // if rendering inside circle, change state immediately or wait for animation to complete
innerCircleStyle={{ alignItems: "center", justifyContent: "center" }} // style for inner animated circle for what you (may) be rendering inside the circle
outerCircleStyle={{}} // style for outer animated circle
renderActiveText={false}
renderInActiveText={false}
switchLeftPx={2} // denominator for logic when sliding to TRUE position. Higher number = more space from RIGHT of the circle to END of the slider
switchRightPx={2} // denominator for logic when sliding to FALSE position. Higher number = more space from LEFT of the circle to BEGINNING of the slider
switchWidthMultiplier={2} // multiplied by the `circleSize` prop to calculate total width of the Switch
switchBorderRadius={20} // Sets the border Radius of the switch slider. If unset, it remains the circleSize.
/>
</View>
</View>
</SafeAreaView>
);
};
export default SettingsComponent;
this happened to me too today, any progress how to fix it?
same problem here any ideas please ?