Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reanimated Chat Flatlist does not scroll to end properly when content size changes #480

Closed
NoureldinAmer opened this issue Jun 20, 2024 · 3 comments
Assignees
Labels
example Anything related to example project question You wanted to clarify something about the usage of the library or have a question about something

Comments

@NoureldinAmer
Copy link

Describe the bug
The reanimated chat flatlist does not scroll to end properly when content size changes, this has been observed when I modified the sample ReanimatedChatFlatlist.tsx code to enable inserting new messages.

Code snippet

import React, { useRef, useState } from "react";
import { FlatList, TextInput, View } from "react-native";
import { useKeyboardHandler } from "react-native-keyboard-controller";
import Animated, {
  useAnimatedStyle,
  useSharedValue,
} from "react-native-reanimated";

import Message from "../../../components/Message";
import { history } from "../../../components/Message/data";

import styles from "./styles";

import type { MessageProps } from "../../../components/Message/types";
import type { ListRenderItem } from "react-native";

const staticReversedMessages = [...history].reverse();

const RenderItem: ListRenderItem<MessageProps> = ({ item, index }) => {
  return <Message key={index} {...item} />;
};

const useGradualAnimation = () => {
  const height = useSharedValue(0);

  useKeyboardHandler(
    {
      onMove: (e) => {
        "worklet";

        height.value = e.height;
      },
      onEnd: (e) => {
        "worklet";

        height.value = e.height;
      },
    },
    []
  );

  return { height };
};

function ReanimatedChatFlatList() {
  const { height } = useGradualAnimation();
  const [messages, setMessages] = useState(staticReversedMessages);
  const [userInput, setUserInput] = useState<string>("");
  const flatListRef = useRef<FlatList>(null);

  const handleSend = () => {
    setUserInput("");
    setMessages((prevMessages) => [
      {
        text: userInput,
        sender: true,
      },
      ...prevMessages,
    ]);
  };

  const fakeView = useAnimatedStyle(
    () => ({
      height: Math.abs(height.value),
    }),
    []
  );

  return (
    <View style={styles.container}>
      <FlatList
        inverted
        initialNumToRender={15}
        contentContainerStyle={styles.contentContainer}
        data={messages}
        renderItem={RenderItem}
        ref={flatListRef}
        onContentSizeChange={(e) => {
          flatListRef.current?.scrollToEnd({
            animated: true,
          });
        }}
      />
      <TextInput
        style={styles.textInput}
        enterKeyHint="send"
        value={userInput}
        onChangeText={setUserInput}
        onSubmitEditing={handleSend}
      />
      <Animated.View style={fakeView} />
    </View>
  );
}

export default ReanimatedChatFlatList;

Repo for reproducing
/example (ReanimatedChatFlatList/index.tsx) has been modified as shown above

To Reproduce
Steps to reproduce the behavior:

  1. Go to 'Chat FlatList component'
  2. Click on 'text field' and add text
  3. Click on "Enter"
  4. See error

Expected behavior
The chat-log scrolls gracefully, to the last sent message (similar to any typical chat app)

Screenshots

Simulator.Screen.Recording.-.iPhone.15.Pro.Max.-.2024-06-20.at.08.28.50.mp4

Smartphone (please complete the following information):

  • Desktop OS: [e.g. Windows 10, MacOS 10.15.5]
  • Device: iPhone 15 Pro Max
  • OS: 17.2
  • RN version: 0.74.2
  • RN architecture: new
  • JS engine: [e.g. JSC, Hermes, v8]
  • Library version: 1.12.3
@kirillzyusko
Copy link
Owner

Hey @NoureldinAmer

I used this code and it works (though scroll is not animated):

import React, { useState } from "react";
import { Button, FlatList, TextInput, View } from "react-native";
import { useKeyboardHandler } from "react-native-keyboard-controller";
import Animated, {
  useAnimatedStyle,
  useSharedValue,
} from "react-native-reanimated";

import Message from "../../../components/Message";
import { history } from "../../../components/Message/data";

import styles from "./styles";

import type { MessageProps } from "../../../components/Message/types";
import type { ListRenderItem } from "react-native";

const reversedMessages = [...history].reverse();

const RenderItem: ListRenderItem<MessageProps> = ({ item, index }) => {
  return <Message key={index} {...item} />;
};

const useGradualAnimation = () => {
  const height = useSharedValue(0);

  useKeyboardHandler(
    {
      onMove: (e) => {
        "worklet";

        height.value = e.height;
      },
      onEnd: (e) => {
        "worklet";

        height.value = e.height;
      },
    },
    [],
  );

  return { height };
};

function ReanimatedChatFlatList() {
  const [messages, setMessages] = useState(reversedMessages);
  const [userInput, setUserInput] = useState<string>("");
  const { height } = useGradualAnimation();

  const fakeView = useAnimatedStyle(
    () => ({
      height: Math.abs(height.value),
    }),
    [],
  );

  const handleSend = (e) => {
    setUserInput("");
    setMessages((prevMessages) => [
      {
        text: userInput,
        sender: true,
      },
      ...prevMessages,
    ]);
  };

  return (
    <View style={styles.container}>
      <FlatList
        inverted
        initialNumToRender={15}
        contentContainerStyle={styles.contentContainer}
        data={messages}
        renderItem={RenderItem}
      />
      <View>
        <TextInput
          style={styles.textInput}
          value={userInput}
          onChangeText={setUserInput}
          onSubmitEditing={handleSend}
        />
        <Button title="Send" onPress={handleSend} />
      </View>
      <Animated.View style={fakeView} />
    </View>
  );
}

export default ReanimatedChatFlatList;

@kirillzyusko
Copy link
Owner

If you would like to avoid instant scrolling and have an animated variant, then you can look into - facebook/react-native#25239
But honestly I didn't find out on how to make this animation 🤷‍♂️

@kirillzyusko kirillzyusko added question You wanted to clarify something about the usage of the library or have a question about something example Anything related to example project labels Jun 25, 2024
@kirillzyusko
Copy link
Owner

I'm going to close that issue, because it's related to example app (which was crafted for demonstration purposes) and not related to the functionality of the library.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
example Anything related to example project question You wanted to clarify something about the usage of the library or have a question about something
Projects
None yet
Development

No branches or pull requests

2 participants