Search code examples
javascriptreactjstypescriptreact-nativerendering

too many re-renders when data moved to a separate component


Currently, I am using this logic to render data on the basis of results from a grapqhl query. This works fine:

 const contacts = () => {
    const { loading, error, data } = useUsersQuery({
      variables: {
        where: { id: 1 },
      },
    });
    if (data) {
      console.log('DATA COMING', data);
      const contactName = data.users.nodes[0].userRelations[0].relatedUser.firstName
        .concat(' ')
        .concat(data.users.nodes[0].userRelations[0].relatedUser.lastName);
      return (
        <View style={styles.users}>
          <View style={styles.item} key={data.users.nodes[0].id}>
            <Thumbnail
              style={styles.thumbnail}
              source={{
                uri:
                  'https://cdn4.iconfinder.com/data/icons/avatars-xmas-giveaway/128/girl_avatar_child_kid-512.png',
              }}></Thumbnail>

            <Text style={styles.userName}>{contactName}</Text>
          </View>
        </View>
      );
    }
  };

  return (
    <SafeAreaView style={{ flex: 1 }}>
      <Container style={{ flex: 1, alignItems: 'center' }}>
        <Item style={styles.addToWhitelist}>
          <Icon name="add" onPress={() => navigation.navigate('AddContact')} />
          <Text style={styles.addToContactTitle}>Add contact</Text>
        </Item>
        <Text onPress={() => navigation.navigate('Home')}>Zurück</Text>
        <View style={{ width: moderateScale(350) }}>
          <Text>Keine Kontacte</Text>
        </View>
        {contacts()}
        {/* <ContactList data={userData}></ContactList> */}
      </Container>
    </SafeAreaView>
  );
};

However, when I make a separate component :

export const ContactList: React.FunctionComponent<UserProps> = ({
  data,
}) => {
  console.log('user called');
  if (!data) return null;
  console.log('DATA COMING', data);
      const contactName = data.users.nodes[0].userRelations[0].relatedUser.firstName
        .concat(' ')
        .concat(data.users.nodes[0].userRelations[0].relatedUser.lastName);
  return (
    <View style={styles.users}>
    <View style={styles.item} key={data.users.nodes[0].id}>
      <Thumbnail
        style={styles.thumbnail}
        source={{
          uri:
            'https://cdn4.iconfinder.com/data/icons/avatars-xmas-giveaway/128/girl_avatar_child_kid-512.png',
        }}></Thumbnail>
      <Text style={styles.userName}>{contactName}</Text>
    </View>
  </View>
  );
};

and call it like this:

 const [userData, setUserData] = useState<UsersQueryHookResult>('');

  const contacts = () => {
    console.log('running');
    const { loading, error, data } = useUsersQuery({
      variables: {
        where: { id: 1 },
      },
    });
    if (data) {
      setUserData(data);
    }
  };

  return (
    <SafeAreaView style={{ flex: 1 }}>
      <Container style={{ flex: 1, alignItems: 'center' }}>
        <Item style={styles.addToWhitelist}>
          <Icon name="add" onPress={() => navigation.navigate('AddContact')} />
          <Text style={styles.addToContactTitle}>Add contact</Text>
        </Item>
        <Text onPress={() => navigation.navigate('Home')}>Zurück</Text>
        <View style={{ width: moderateScale(350) }}>
          <Text>Keine Kontacte</Text>
        </View>
        {/* {contacts()} */}
        <ContactList data={userData}></ContactList>
      </Container>
    </SafeAreaView>
  );
};

However, this gives me a too many re-renders issue. What am I missing? Probably something basic. I also tried using useEffects but I can't run a graphql query hook inside it. That gives me an invalid hook call error.


Solution

  • It seems your running in an endless recursion.

    If you call contacts in you render block it causes a setState (through setUserData) which renders, so contacts is called once again and so on till infinite (or till the error).