From what I learnd everywhere, it seems like useState set doesn't chage the value immediately as you know.
What I want to inplement: In my simple app, there is a button for removing a value from an array with setState, and at the same time navigating to another screen. (Like, when there is no item on the array, then it navigates to another screen)
Here are my initial codes:
import React, { useState, useEffect } from "react";
import { View, Button } from "react-native";
function Home({ navigation }) {
const [array, setArray] = useState(["X"]);
const removeValue = () => {
setArray((current) => {
return current.filter((item) => item !== array[0]);
});
console.log("array", array); //It still refers to the old value.
if (JSON.stringify(array) === JSON.stringify([])) {
navigation.navigate("About");
}
};
return (
<View>
<Button title="GoToAbout" onPress={removeValue} />
</View>
);
}
export default Home;
import React from "react";
import { View, Text } from "react-native";
function About() {
return (
<View>
<Text>There is no item in your list.</Text>
</View>
);
}
export default About;
import { StyleSheet, Text, View } from "react-native";
import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import Home from "./Home";
import About from "./About";
const Stack = createNativeStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="About" component={About} />
</Stack.Navigator>
</NavigationContainer>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center",
},
});
Because state doesn't change the value immediately, google serch says you can use useEffect to deal with the problem, so I tried it with useEffect. Here is the code with useEffect:
import React, { useState, useEffect } from "react";
import { View, Button } from "react-native";
function Home({ navigation }) {
const [array, setArray] = useState(["X"]);
const removeValue = () => {
setArray((current) => {
return current.filter((item) => item !== array[0]);
});
};
useEffect(() => {
if (JSON.stringify(array) === JSON.stringify([])) {
console.log("array", array);
navigation.navigate("About");
}
}, [array]);
//Using this second aug [array] doesn't work well, because I use 'array' in everywhere in my app, so it accidentally renders where I don't want it to render.
return (
<View>
<Button title="GoToAbout" onPress={removeValue} />
</View>
);
}
export default Home;
That worked beautifully here. However in my app, I use the 'array' in everywhere, so using it as the second aug in useEffect doesn't work well because it accidentally renders where I don't want it to do.
So, now I'm stack. Is there any other way that soloves this problem?
Thank you in advance.
OK. So it's not necessary to use the callback form of setArray
here.
Instead, let's wrap up the removeValue
function in a useCallback
hook and use the non-callback version of setArray
:
const removeValue = React.useCallback(() => {
const newArrayValue = array.filter((item) => item !== array[0])
setArray(newArrayValue);
// ... now we know what the new value is already... it's stored in
// newArrayValue
if (newArrayValue.length === 0) { //an easier way to check for empty
navigation.navigate("About");
}
}, [array, navigation]);