0

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.

  • Does this answer your question? [The useState set method is not reflecting a change immediately](https://stackoverflow.com/questions/54069253/the-usestate-set-method-is-not-reflecting-a-change-immediately) – Brian Thompson Mar 02 '23 at 15:27

1 Answers1

1

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]);
spender
  • 117,338
  • 33
  • 229
  • 351
  • This works like a charm! I really couldn't come up with that great way by myself. However, this works perfectly in my code here, but somehow doesn't work in my real app even tho it has the same structure as this one...I needed to press a button twice to get it to navigate. Now I'm really confused. But anyhow, thank you so much for your help. I appreciate it! – sahasrabhuja neuron Mar 02 '23 at 16:34
  • After playing around with this thing several times and then I removed the useCallback from the function, somehow it finally started working the way I want! Maybe I put something wrong into the arguments? Anyway, thank you so much! I appreciate it – sahasrabhuja neuron Mar 04 '23 at 03:37
  • That would imply that you did not correctly list the dependencies of the callback in the useCallback second parameter. – spender Mar 04 '23 at 15:25