From 265772c40bdc498e7721bafab74a5be8d6cf6fcd Mon Sep 17 00:00:00 2001 From: Bao Nguyen Date: Fri, 14 Aug 2026 08:52:54 +0700 Subject: [PATCH] docs: make chat app "Complete example" copy/paste ready The "Complete example" on the "Building a chat app" page did not compile when copied into an app: it referenced `INITIAL_MESSAGES`, `Message` and `styles` without defining them, rendered `` without importing it, and left `StyleSheet`/`View` imported but unused. Replace the snippet with the version posted in the issue, which defines the `Message` component and the `styles` sheet, seeds `messages` inline, imports `Text`, inserts new messages at the head of the history for the inverted list, and exports the screen as default. Applied to the current docs and to the 1.22.0 versioned copy, which are byte-identical. --- docs/docs/guides/building-chat-app.mdx | 93 +++++++++++++++++-- .../guides/building-chat-app.mdx | 93 +++++++++++++++++-- 2 files changed, 168 insertions(+), 18 deletions(-) diff --git a/docs/docs/guides/building-chat-app.mdx b/docs/docs/guides/building-chat-app.mdx index 621cf7c499..a9d4af791e 100644 --- a/docs/docs/guides/building-chat-app.mdx +++ b/docs/docs/guides/building-chat-app.mdx @@ -517,18 +517,19 @@ Here is a complete chat screen that ties together all the pieces — `KeyboardCh import React, { forwardRef, useCallback, useRef, useState } from "react"; import { FlatList, + type LayoutChangeEvent, + type ScrollViewProps, StyleSheet, + Text, TextInput, TouchableOpacity, View, - type LayoutChangeEvent, - type ScrollViewProps, } from "react-native"; import { KeyboardChatScrollView, + type KeyboardChatScrollViewRef, KeyboardGestureArea, KeyboardStickyView, - type KeyboardChatScrollViewRef, } from "react-native-keyboard-controller"; import { useSharedValue, withTiming } from "react-native-reanimated"; import { @@ -538,8 +539,17 @@ import { import type { KeyboardChatScrollViewProps } from "react-native-keyboard-controller"; +function Message({ text, sender }: { text: string; sender: boolean }) { + return ( + + {text} + + ); +} + const MARGIN = 8; const INPUT_HEIGHT = 42; +const TEXT_INPUT_HEIGHT = INPUT_HEIGHT + MARGIN; // Wrapper for virtualized lists const ChatScrollView = forwardRef< @@ -563,7 +573,9 @@ const ChatScrollView = forwardRef< function ChatScreen() { const textInputRef = useRef(null); const textRef = useRef(""); - const [messages, setMessages] = useState(INITIAL_MESSAGES); + const [messages, setMessages] = useState([ + { id: "1786111174702", text: "Hello", sender: false }, + ]); const { bottom } = useSafeAreaInsets(); const extraContentPadding = useSharedValue(0); @@ -576,9 +588,16 @@ function ChatScreen() { const onSend = useCallback(() => { const text = textRef.current.trim(); - if (!text) return; - setMessages((prev) => [...prev, { id: String(Date.now()), text }]); + if (!text) { + return; + } + + setMessages((prev) => [ + // for inverted list we need to insert new message in the beginning of the history + { id: String(Date.now()), text, sender: true }, + ...prev, + ]); textInputRef.current?.clear(); textRef.current = ""; }, []); @@ -602,9 +621,9 @@ function ChatScreen() { textInputNativeID="chat-input" > item.id} renderItem={({ item }) => } renderScrollComponent={renderScrollComponent} @@ -622,7 +641,7 @@ function ChatScreen() { onChangeText={(text) => (textRef.current = text)} onLayout={onInputLayout} /> - + Send @@ -630,6 +649,62 @@ function ChatScreen() { ); } + +const container = { + borderRadius: 10, + padding: 10, + margin: 10, + marginVertical: 5, + maxWidth: "80%" as const, +}; + +const styles = StyleSheet.create({ + container: { + justifyContent: "flex-end", + flex: 1, + backgroundColor: "#3A3A3C", + }, + input: { + flex: 1, + margin: MARGIN, + marginBottom: 0, + padding: MARGIN, + borderRadius: 99, + borderWidth: 1, + borderColor: "#BCBCBC", + backgroundColor: "#3A3A3C66", + }, + composer: { + position: "absolute", + width: "100%", + minHeight: TEXT_INPUT_HEIGHT, + flexDirection: "row", + }, + send: { + right: MARGIN, + padding: MARGIN, + marginTop: MARGIN, + backgroundColor: "white", + justifyContent: "center", + borderRadius: 16, + marginLeft: MARGIN, + }, + senderContainer: { + alignSelf: "flex-end", + backgroundColor: "#F8F8FC", + ...container, + }, + recipientContainer: { + alignSelf: "flex-start", + backgroundColor: "#64D2FF", + ...container, + }, + message: { + color: "#000000", + }, +}); + +export default ChatScreen; ``` Or play with the code in live mode directly in the browser: diff --git a/docs/versioned_docs/version-1.22.0/guides/building-chat-app.mdx b/docs/versioned_docs/version-1.22.0/guides/building-chat-app.mdx index 621cf7c499..a9d4af791e 100644 --- a/docs/versioned_docs/version-1.22.0/guides/building-chat-app.mdx +++ b/docs/versioned_docs/version-1.22.0/guides/building-chat-app.mdx @@ -517,18 +517,19 @@ Here is a complete chat screen that ties together all the pieces — `KeyboardCh import React, { forwardRef, useCallback, useRef, useState } from "react"; import { FlatList, + type LayoutChangeEvent, + type ScrollViewProps, StyleSheet, + Text, TextInput, TouchableOpacity, View, - type LayoutChangeEvent, - type ScrollViewProps, } from "react-native"; import { KeyboardChatScrollView, + type KeyboardChatScrollViewRef, KeyboardGestureArea, KeyboardStickyView, - type KeyboardChatScrollViewRef, } from "react-native-keyboard-controller"; import { useSharedValue, withTiming } from "react-native-reanimated"; import { @@ -538,8 +539,17 @@ import { import type { KeyboardChatScrollViewProps } from "react-native-keyboard-controller"; +function Message({ text, sender }: { text: string; sender: boolean }) { + return ( + + {text} + + ); +} + const MARGIN = 8; const INPUT_HEIGHT = 42; +const TEXT_INPUT_HEIGHT = INPUT_HEIGHT + MARGIN; // Wrapper for virtualized lists const ChatScrollView = forwardRef< @@ -563,7 +573,9 @@ const ChatScrollView = forwardRef< function ChatScreen() { const textInputRef = useRef(null); const textRef = useRef(""); - const [messages, setMessages] = useState(INITIAL_MESSAGES); + const [messages, setMessages] = useState([ + { id: "1786111174702", text: "Hello", sender: false }, + ]); const { bottom } = useSafeAreaInsets(); const extraContentPadding = useSharedValue(0); @@ -576,9 +588,16 @@ function ChatScreen() { const onSend = useCallback(() => { const text = textRef.current.trim(); - if (!text) return; - setMessages((prev) => [...prev, { id: String(Date.now()), text }]); + if (!text) { + return; + } + + setMessages((prev) => [ + // for inverted list we need to insert new message in the beginning of the history + { id: String(Date.now()), text, sender: true }, + ...prev, + ]); textInputRef.current?.clear(); textRef.current = ""; }, []); @@ -602,9 +621,9 @@ function ChatScreen() { textInputNativeID="chat-input" > item.id} renderItem={({ item }) => } renderScrollComponent={renderScrollComponent} @@ -622,7 +641,7 @@ function ChatScreen() { onChangeText={(text) => (textRef.current = text)} onLayout={onInputLayout} /> - + Send @@ -630,6 +649,62 @@ function ChatScreen() { ); } + +const container = { + borderRadius: 10, + padding: 10, + margin: 10, + marginVertical: 5, + maxWidth: "80%" as const, +}; + +const styles = StyleSheet.create({ + container: { + justifyContent: "flex-end", + flex: 1, + backgroundColor: "#3A3A3C", + }, + input: { + flex: 1, + margin: MARGIN, + marginBottom: 0, + padding: MARGIN, + borderRadius: 99, + borderWidth: 1, + borderColor: "#BCBCBC", + backgroundColor: "#3A3A3C66", + }, + composer: { + position: "absolute", + width: "100%", + minHeight: TEXT_INPUT_HEIGHT, + flexDirection: "row", + }, + send: { + right: MARGIN, + padding: MARGIN, + marginTop: MARGIN, + backgroundColor: "white", + justifyContent: "center", + borderRadius: 16, + marginLeft: MARGIN, + }, + senderContainer: { + alignSelf: "flex-end", + backgroundColor: "#F8F8FC", + ...container, + }, + recipientContainer: { + alignSelf: "flex-start", + backgroundColor: "#64D2FF", + ...container, + }, + message: { + color: "#000000", + }, +}); + +export default ChatScreen; ``` Or play with the code in live mode directly in the browser: