Search code examples
reactjsreact-nativeuse-effectuse-state

React native: useState not updating correctly


I'm new to react native and currently struggling with an infinite scroll listview. It's a calendar list that need to change depending on the selected company (given as prop). The thing is: the prop (and also the myCompany state are changed, but in the _loadMoreAsync method both prop.company as well as myCompany do hold their initial value.

import * as React from 'react';
import { FlatList } from 'react-native';
import * as Api from '../api/api';
import InfiniteScrollView from 'react-native-infinite-scroll-view';

function CalenderFlatList(props: { company: any }) {
  const [myCompany, setMyCompany] = React.useState(null);
  const [data, setData] = React.useState([]);
  const [canLoadMore, setCanLoadMore] = React.useState(true);
  const [startDate, setStartDate] = React.useState(undefined);

  let loading = false;

  React.useEffect(() => {
    setMyCompany(props.company);
  }, [props.company]);

  React.useEffect(() => {
    console.log('set myCompany to ' + (myCompany ? myCompany.name : 'undefined'));
    _loadMoreAsync();
  }, [myCompany]);

  async function _loadMoreAsync() {
    if ( loading )
      return;

    loading = true;

    if ( myCompany == null ) {
      console.log('no company selected!');
      return;
    } else {
      console.log('use company: ' + myCompany.name);
    }

    Api.fetchCalendar(myCompany, startDate).then((result: any) => {
      // code is a little more complex here to keep the already fetched entries in the list...
      setData(result);

      // to above code also calculates the last day +1 for the next call
      setStartDate(lastDayPlusOne);

      loading = false;
    });
  }

  const renderItem = ({ item }) => {
    // code to render the item
  }

  return (
    <FlatList
      data={data}
      renderScrollComponent={props => <InfiniteScrollView {...props} />}
      renderItem={renderItem}
      keyExtractor={(item: any) => '' + item.uid }
      canLoadMore={canLoadMore}
      onLoadMoreAsync={() => _loadMoreAsync() }
    />
  );
}

What I don't understand here is why myCompany is not updating at all in _loadMoreAsync while startDate updates correctly and loads exactly the next entries for the calendar.

After the prop company changes, I'd expect the following output:

set myCompany to companyName

use company companyName

But instead i get:

set myCompany to companyName

no company selected!

I tried to reduce the code a bit to strip it down to the most important parts. Any suggestions on this?


Solution

  • After sleeping two nights over the problem I solved it by myself. The cause was an influence of another piece of code that used React.useCallback(). And since "useCallback will return a memoized version of the callback that only changes if one of the dependencies has changed" (https://reactjs.org/docs/hooks-reference.html#usecallback) the code worked with the old (or initial) state of the variables.

    After creating the whole page new from scratch I found this is the reason for that behavior.