Home > front end >  How to render component via FlatList?
How to render component via FlatList?

Time:05-21

Using react native with typescript and redux toolkit

Hi I'm bothering with render a list of messages via FlatList. By ScrollView everything rendering good but I need to implement infiniti scroll. So I'm doing something like this

const MessagesScreen = () => {
  const companyId = useAppSelector(getCompanyId);
  const userId = useAppSelector(getUserId);

  const {
    data: messages,
    isLoading,
    refetch
  } = useGetMessagesQuery({ userId, companyId });
  useFocusEffect(refetch);

  return (
    <FlatList
      data={messages}
      renderItem={() => {
        <Messages messages={messages} />;
      }}
    />
  );
};

In return() I'm trying to render FlatList with component Messages which is down here:

const Messages = ({ messages }: { messages: Message[] }) => {
  const navigation =
    useNavigation<RootStackScreenProps<'DrawerNavigator'>['navigation']>();
  const { colors } = useTheme();

  return (
    <View style={styles.container}>
      {messages.map(message => {
        const createdAt = message.created_at;
        const isRead = message.read;
        const icon = isRead ? 'email-open-outline' : 'email-outline';
        const onClick = () => {
          navigation.navigate('Message', {
            messageId: message.id
          });
        };

        return (
          <TouchableOpacity key={message.id} onPress={onClick}>
            <View
              style={[styles.message, { borderBottomColor: colors.separator }]}
            >
              <View style={styles.iconPart}>
                <Icon
                  name={icon}
                  type="material-community"
                  style={
                    isRead
                      ? { color: colors.separator }
                      : { color: colors.inputFocus }
                  }
                  size={24}
                ></Icon>
              </View>
              <View style={styles.bodyPart}>
                <Text
                  numberOfLines={1}
                  style={[isRead ? styles.readSubject : styles.unReadSubject]}
                >
                  {message.subject}
                </Text>
                <Text
                  numberOfLines={1}
                  style={[isRead ? styles.readBody : styles.unReadBody]}
                >
                  {message.body}
                </Text>
              </View>
              <View style={styles.datePart}>
                <Text style={{ color: colors.shadow }}>
                  {dayjs(createdAt).fromNow()}
                </Text>
              </View>
            </View>
          </TouchableOpacity>
        );
      })}
    </View>
  );
};

Actually behaviour is just rendering white screen with error

Possible Unhandled Promise Rejection (id: 17):
Error: Objects are not valid as a React child (found: object with keys {id, msg_type, created_at, subject, body, author, company_id, read}). If you meant to render a collection of children, use an array instead.

CodePudding user response:

there is problem with your call back function: you are not returning Messages component

1:Remove curly braces

 return (
    <FlatList
      data={messages}
      renderItem={() => <Messages messages={messages}/> }
    />
  );

2:Add return statement

 return (
    <FlatList
      data={messages}
      renderItem={() => {
       return <Messages messages={messages} />;
      }}
    />
  );

CodePudding user response:

Couple things:

You're using the renderItem callback incorrectly:

<FlatList
      data={messages}
      renderItem={() => {
      // ^ ignoring the renderItem props
        return <Messages messages={messages} />;
      }}
    />

Here, for each item in the messages array, you're rendering a component and passing all the messages into it. So you'll get repeated elements.

The renderItem callback is passed {item, index} where item is the CURRENT item in the array (index is the index into the array)

See docs here: https://reactnative.dev/docs/flatlist

The usual thing is the renderItem callback renders ONE item at a time, like this:

<FlatList
      data={messages}
      renderItem={({item}) => {
        return <Message message={item} />;
      }}
    />

e.g. I'd make a <Message/> component that renders one item only.

  • Related