My Callback returning same state after calling it again and again
i am new to react hooks in react classes i could have used shouldcomponentupdate and could have solved this issue
but there isn't params in usecallback hook
import React, {
useLayoutEffect,
useState,
useCallback,
useEffect,
} from "react";
import { StyleSheet, Text, View, Platform, YellowBox } from "react-native";
import { HeaderButtons, Item } from "react-navigation-header-buttons";
import HeaderButton from "../components/HeaderButton";
import { Switch } from "react-native-paper";
import Colors from "../constants/Colors";
//check use callback value first
YellowBox.ignoreWarnings([
"Non-serializable values were found in the navigation state",
]);
const FilterSwitch = ({ label, state, onChange }) => (
<View style={styles.filterContainer}>
<Text>{label}</Text>
<Switch
value={state}
trackColor={{ true: Colors.primaryColor }}
thumbColor={Platform.OS === "android" ? Colors.primaryColor : ""}
onValueChange={onChange}
/>
</View>
);
const FiltersScreen = ({ navigation }) => {
const [isGlutenFree, setIsGlutenFree] = useState(false);
const [isLactoseFree, setIsLactoseFree] = useState(false);
const [isVegan, setIsVegan] = useState(false);
const [isVegetarian, setIsVegetarian] = useState(false);
const saveFilters = useCallback(() => {
console.log(isGlutenFree);
const appliedFilters = {
glutenFree: isGlutenFree,
lactoseFree: isLactoseFree,
vegan: isVegan,
isVegetarian: isVegetarian,
};
console.log(appliedFilters);
}, [isGlutenFree, isLactoseFree, isVegan, isVegetarian]);
useLayoutEffect(() => {
navigation.setOptions({
headerTitle: "Filter Meals",
headerLeft: () => (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title="Menu"
iconName="ios-menu"
onPress={() => {
navigation.toggleDrawer();
}}
/>
</HeaderButtons>
),
headerRight: () => (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title="Save"
iconName="ios-save"
onPress={() => saveFilters()}
/>
</HeaderButtons>
),
});
}, [navigation]);
return (
<View style={styles.screen}>
<Text style={styles.title}>Available Filters / Restrictions</Text>
<FilterSwitch
label="Gluten Free"
state={isGlutenFree}
onChange={(newValue) => {
setIsGlutenFree(newValue);
}}
/>
<FilterSwitch
label="Lactos Free"
state={isLactoseFree}
onChange={(newValue) => setIsLactoseFree(newValue)}
/>
<FilterSwitch
label="Vegan Free"
state={isVegan}
onChange={(newValue) => setIsVegan(newValue)}
/>
<FilterSwitch
label="Vegetarian Free"
state={isVegetarian}
onChange={(newValue) => setIsVegetarian(newValue)}
/>
</View>
);
};
const styles = StyleSheet.create({
screen: {
flex: 1,
alignItems: "center",
},
filterContainer: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
width: "80%",
marginVertical: 15,
},
title: {
fontFamily: "open-sans-bold",
fontSize: 22,
margin: 20,
textAlign: "center",
},
});
export default FiltersScreen;
How can i solve this problem? I Have read official docs and i couldn't find any related issues there
The answer: They're just queues setState , and React. useState create queues for React core to update the state object of a React component. So the process to update React state is asynchronous for performance reasons. That's why changes don't feel immediate.
To update the state, call the state updater function with the new state setState(newState) . Alternatively, if you need to update the state based on the previous state, supply a callback function setState(prevState => newState) .
The useCallback hook is used when you have a component in which the child is rerendering again and again without need. Pass an inline callback and an array of dependencies. useCallback will return a memoized version of the callback that only changes if one of the dependencies has changed.
The issue with your code is that, even though you have provided useCallback with all dependecy array, you are only using the first closure value of the function within onPress={() => saveFilters()} since this code is executed inside useLayoutEffect and that is run only on navigation change
The solution here is to update navigation options on both navigation change and on saveFilters change
useLayoutEffect(() => {
navigation.setOptions({
headerTitle: "Filter Meals",
headerLeft: () => (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title="Menu"
iconName="ios-menu"
onPress={() => {
navigation.toggleDrawer();
}}
/>
</HeaderButtons>
),
headerRight: () => (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title="Save"
iconName="ios-save"
onPress={() => saveFilters()}
/>
</HeaderButtons>
),
});
}, [navigation, saveFilters]);
P.S. This is the kind of situation where I feel hooks implementation sometimes becomes hacky or inefficient. Also debugging
closuresis way more difficult then debuggingcontext(this in class component)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With