0

I am using hooks in React Native. This is my code:



useEffect(() => {

    if (var1.length > 0 ){


      let sym = [];
      var1.map((items) => {
        let count = 0;
        state.map((stateItems) => {

          if(items === stateItems.name) {
            count = count + 1;
          }

        })

        if (count === 0) {
          sym.push(items)
        }
      });



      async function getAllStates (sym) {
        let stateValues = [];
        await Promise.all(sym.map(obj =>
          axios.get(ServerURL + "/note?name=" + obj).then(response => {
            stateValues.push(response.data[0]);
          })
        )).then(() =>{
          setNewItem(stateValues);
        });

      }


      getAllStates (sym);

    }
    }, [var1]);

useEffect(() => {
      let stateValues = state;
      for( let count = 0 ; count < newItem.length; count++ ){
        stateValues.push(newItem[count]);
      }

      setState(stateValues);

    }, [newItem]);

This runs successfully without any errors. However, when the state is displayed as below, I am not seeing the latest value added in the state. It shows all the previous values. When I refresh the whole application, I am able to see my value added.

 return (
    <View style={styles.container}>

    <Text  style = {{color:"white"}}>
        {
          state.map( (item, key) =>{
            return(
              <Text key = {key} style = {{color:"white"}}> {item.name} </Text>
            )
          })
        }
    </Text>
    </View>
  );

Can someone tell me why this is happening? I want to see the data render immediately after the axios call. I am using React Native.

bheadr92
  • 33
  • 1
  • 5
  • Think about what's happening here - you're setting off multiple promises, all of which will try to update the state but all of which assume the *initial* state. It would be better to put the `.then` on the `Promise.all`. – jonrsharpe May 18 '20 at 09:33
  • ^ or `setState(state => [...state, response.data[0]]);` – Thomas May 18 '20 at 10:29
  • and your filter written as such: `const sym = var1.filter(items => !state.some(({ name }) => items === name));` – Thomas May 18 '20 at 10:32
  • i tried after promise.all as per the edited code, it is still not giving me anything different. – bheadr92 May 18 '20 at 11:00
  • when i force update using :https://stackoverflow.com/questions/53215285/how-can-i-force-component-to-re-render-with-hooks-in-react it works fine. However, i am looking for a better fix if anyone can provide? – bheadr92 May 18 '20 at 11:20

1 Answers1

0

when i force update using :stackoverflow.com/questions/53215285/... it works fine. However, i am looking for a better fix if anyone can provide?

This should do:

useEffect(() => {
  var1.forEach(async (name) => {
    if (state.some(item => item.name === name)) return;

    const response = await axios.get(ServerURL + "/note?name=" + name);

    setState(state => [...state, response.data[0]]);
  });
}, [var1]);

I still see two issues in your approach:

  • this code may start the same ajax request multiple times before the result of the firstz ajax-request is added to state; this also means that the result for the same name may be added multiple times to state.

  • for each item of var1 times each item of state, this is an O(n*m) problem or in this case basically O(n²) as m is pretty fast catching up to n. You should find a better approach here.

And I'm almost certain that [var1] is wrong here as the dependency for useEffect. But you'd need to show where this value comes from to fix that, too.

Thomas
  • 11,958
  • 1
  • 14
  • 23