UI การแชทที่สมบูรณ์แบบที่สุดสำหรับ React Native & Web
เว็บสาธิต ?
สนามเด็กเล่นของว่าง GiftedChat
Coding Bootcamp ในปารีสก่อตั้งโดย Farid Safi
คลิกเพื่อเรียนรู้เพิ่มเติม
API/เซิร์ฟเวอร์แชทที่ปรับขนาดได้เขียนใน Go
ทัวร์ API | โต้ตอบบทช่วยสอน Native Gifted
เอ็นจิ้นแอพที่สมบูรณ์พร้อม GiftedChat
ลองดู GitHub ของเรา
react-native-web
สามารถ กำหนดค่าเว็บได้ (ตั้งแต่ 0.10.0)เส้นด้าย:
yarn add react-native-gifted-chat react-native-reanimated react-native-safe-area-context react-native-get-random-values
นาทีต่อนาที:
npm install --save react-native-gifted-chat react-native-reanimated react-native-safe-area-context react-native-get-random-values
งานเอ็กซ์โป
npx expo install react-native-gifted-chat react-native-reanimated react-native-safe-area-context react-native-get-random-values
npx pod-install
ปฏิบัติตามคำแนะนำ: บริบทพื้นที่ปลอดภัยแบบโต้ตอบ
ปฏิบัติตามคำแนะนำ: react-native-reanimated
0.11.0
video
ได้ แต่คุณต้องจัดเตรียมอุปกรณ์ประกอบฉาก renderMessageVideo
TEST_ID
จะถูกส่งออกเป็นค่าคงที่ที่สามารถใช้ในไลบรารีการทดสอบที่คุณเลือกได้
Gifted Chat ใช้ onLayout
เพื่อกำหนดความสูงของคอนเทนเนอร์แชท หากต้องการทริกเกอร์ onLayout
ในระหว่างการทดสอบ คุณสามารถเรียกใช้โค้ดต่อไปนี้ได้
const WIDTH = 200 ; // or any number
const HEIGHT = 2000 ; // or any number
const loadingWrapper = getByTestId ( TEST_ID . LOADING_WRAPPER )
fireEvent ( loadingWrapper , 'layout' , {
nativeEvent : {
layout : {
width : WIDTH ,
height : HEIGHT ,
} ,
} ,
} )
import React , { useState , useCallback , useEffect } from 'react'
import { GiftedChat } from 'react-native-gifted-chat'
export function Example ( ) {
const [ messages , setMessages ] = useState ( [ ] )
useEffect ( ( ) => {
setMessages ( [
{
_id : 1 ,
text : 'Hello developer' ,
createdAt : new Date ( ) ,
user : {
_id : 2 ,
name : 'React Native' ,
avatar : 'https://placeimg.com/140/140/any' ,
} ,
} ,
] )
} , [ ] )
const onSend = useCallback ( ( messages = [ ] ) => {
setMessages ( previousMessages =>
GiftedChat . append ( previousMessages , messages ) ,
)
} , [ ] )
return (
< GiftedChat
messages = { messages }
onSend = { messages => onSend ( messages ) }
user = { {
_id : 1 ,
} }
/>
)
}
ดู App.tsx
สำหรับการสาธิตการทำงาน!
ดูไฟล์ใน example/example-slack-message
สำหรับตัวอย่างวิธีแทนที่ UI เริ่มต้นเพื่อสร้างสิ่งที่ดูเหมือน Slack มากขึ้น โดยแสดงชื่อผู้ใช้และข้อความทั้งหมดทางด้านซ้าย
เช่น ข้อความแชท
export interface IMessage {
_id : string | number
text : string
createdAt : Date | number
user : User
image ?: string
video ?: string
audio ?: string
system ?: boolean
sent ?: boolean
received ?: boolean
pending ?: boolean
quickReplies ?: QuickReplies
}
{
_id : 1 ,
text : 'My message' ,
createdAt : new Date ( Date . UTC ( 2016 , 5 , 11 , 17 , 20 , 0 ) ) ,
user : {
_id : 2 ,
name : 'React Native' ,
avatar : 'https://facebook.github.io/react/img/logo_og.png' ,
} ,
image : 'https://facebook.github.io/react/img/logo_og.png' ,
// You can also add a video prop:
video : 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4' ,
// Mark the message as sent, using one tick
sent : true ,
// Mark the message as received, using two tick
received : true ,
// Mark the message as pending with a clock loader
pending : true ,
// Any additional custom parameters are passed through
}
เช่น ข้อความระบบ
{
_id : 1 ,
text : 'This is a system message' ,
createdAt : new Date ( Date . UTC ( 2016 , 5 , 11 , 17 , 20 , 0 ) ) ,
system : true ,
// Any additional custom parameters are passed through
}
เช่น ข้อความแชทพร้อมตัวเลือกตอบกลับด่วน
ดูประชาสัมพันธ์ #1211
interface Reply {
title : string
value : string
messageId ?: number | string
}
interface QuickReplies {
type : 'radio' | 'checkbox'
values : Reply [ ]
keepIt ?: boolean
}
{
_id : 1 ,
text : 'This is a quick reply. Do you love Gifted Chat? (radio) KEEP IT' ,
createdAt : new Date ( ) ,
quickReplies : {
type : 'radio' , // or 'checkbox',
keepIt : true ,
values : [
{
title : '? Yes' ,
value : 'yes' ,
} ,
{
title : '? Yes, let me show you with a picture!' ,
value : 'yes_picture' ,
} ,
{
title : '? Nope. What?' ,
value : 'no' ,
} ,
] ,
} ,
user : {
_id : 2 ,
name : 'React Native' ,
} ,
} ,
{
_id : 2 ,
text : 'This is a quick reply. Do you love Gifted Chat? (checkbox)' ,
createdAt : new Date ( ) ,
quickReplies : {
type : 'checkbox' , // or 'radio',
values : [
{
title : 'Yes' ,
value : 'yes' ,
} ,
{
title : 'Yes, let me show you with a picture!' ,
value : 'yes_picture' ,
} ,
{
title : 'Nope. What?' ,
value : 'no' ,
} ,
] ,
} ,
user : {
_id : 2 ,
name : 'React Native' ,
} ,
}
messageContainerRef
(การอ้างอิง FlatList) - อ้างอิงถึงแฟลตลิสต์textInputRef
(การอ้างอิง TextInput) - อ้างอิงถึงการป้อนข้อความmessages
(อาร์เรย์) - ข้อความที่จะแสดงisTyping
(Bool) - สถานะตัวบ่งชี้การพิมพ์; ค่าเริ่มต้น false
หากคุณใช้ renderFooter
มันจะแทนที่สิ่งนี้text
(สตริง) - ป้อนข้อความ; ค่าเริ่มต้นคือ undefined
แต่หากระบุไว้ มันจะแทนที่สถานะภายในของ GiftedChat (เช่น สำหรับ redux; ดูหมายเหตุด้านล่าง)placeholder
(สตริง) - ตัวยึดตำแหน่งเมื่อ text
ว่างเปล่า ค่าเริ่มต้นคือ 'Type a message...'
messageIdGenerator
(ฟังก์ชัน) - สร้างรหัสสำหรับข้อความใหม่ ค่าเริ่มต้นเป็น UUID v4 สร้างโดย uuiduser
(Object) - ผู้ใช้ส่งข้อความ: { _id, name, avatar }
onSend
(ฟังก์ชั่น) - โทรกลับเมื่อส่งข้อความalwaysShowSend
(Bool) - แสดงปุ่มส่งเสมอในการเขียนข้อความอินพุต; ค่าเริ่มต้น false
แสดงเฉพาะเมื่อการป้อนข้อความไม่ว่างเปล่าlocale
(String) - สถานที่เพื่อแปลวันที่ คุณต้องนำเข้าสถานที่ที่คุณต้องการก่อน (เช่น require('dayjs/locale/de')
หรือ import 'dayjs/locale/fr'
)timeFormat
(String) - รูปแบบที่จะใช้สำหรับการแสดงผลครั้ง; ค่าเริ่มต้นคือ 'LT'
(ดูรูปแบบ Day.js)dateFormat
(String) - รูปแบบที่จะใช้สำหรับการแสดงผลวันที่; ค่าเริ่มต้นคือ 'll'
(ดูรูปแบบ Day.js)loadEarlier
(Bool) - เปิดใช้งานปุ่ม "โหลดข้อความก่อนหน้า" ซึ่งจำเป็นสำหรับ infiniteScroll
onLoadEarlier
(ฟังก์ชัน) - โทรกลับเมื่อโหลดข้อความก่อนหน้าisLoadingEarlier
(Bool) - แสดง ActivityIndicator
เมื่อโหลดข้อความก่อนหน้าrenderLoading
(ฟังก์ชัน) - แสดงผลมุมมองการโหลดเมื่อเริ่มต้นrenderLoadEarlier
(ฟังก์ชัน) - ปุ่ม "โหลดข้อความก่อนหน้า" แบบกำหนดเองrenderAvatar
(ฟังก์ชัน) - อวตารข้อความที่กำหนดเอง; ตั้งค่าเป็น null
เพื่อไม่ให้แสดงอวาตาร์ใดๆ สำหรับข้อความshowUserAvatar
(Bool) - ว่าจะเรนเดอร์อวาตาร์สำหรับผู้ใช้ปัจจุบันหรือไม่ ค่าเริ่มต้นคือ false
แสดงเฉพาะรูปประจำตัวสำหรับผู้ใช้รายอื่นเท่านั้นshowAvatarForEveryMessage
(Bool) - เมื่อเป็นเท็จ อวาตาร์จะแสดงเฉพาะเมื่อมีข้อความติดต่อกันจากผู้ใช้คนเดียวกันในวันเดียวกันเท่านั้น ค่าเริ่มต้นเป็น false
onPressAvatar
(ฟังก์ชั่น( user
)) - โทรกลับเมื่อมีการแตะข้อความประจำตัวonLongPressAvatar
(ฟังก์ชั่น ( user
)) - โทรกลับเมื่ออวตารข้อความถูกกดค้างไว้renderAvatarOnTop
(Bool) - แสดงผลอวาตาร์ข้อความที่ด้านบนของข้อความที่ต่อเนื่องกัน แทนที่จะเป็นด้านล่าง ค่าเริ่มต้นเป็น false
renderBubble
(ฟังก์ชัน) - ฟองข้อความแบบกำหนดเองrenderTicks
(ฟังก์ชั่น ( message
)) - ตัวบ่งชี้เห็บที่กำหนดเองเพื่อแสดงสถานะข้อความrenderSystemMessage
(ฟังก์ชัน) - ข้อความระบบแบบกำหนดเองonPress
(ฟังก์ชั่น( context
, message
)) - โทรกลับเมื่อกดฟองข้อความonLongPress
(Function( context
, message
)) - โทรกลับเมื่อฟองข้อความถูกกดค้างไว้ (ดูตัวอย่างการใช้ showActionSheetWithOptions()
)inverted
(Bool) - กลับลำดับการแสดง messages
; ค่าเริ่มต้นเป็น true
renderUsernameOnMessage
(Bool) - ระบุว่าจะแสดงชื่อผู้ใช้ภายในกรอบข้อความหรือไม่ ค่าเริ่มต้นเป็น false
renderUsername
(ฟังก์ชัน) - คอนเทนเนอร์ชื่อผู้ใช้แบบกำหนดเองrenderMessage
(ฟังก์ชัน) - ที่เก็บข้อความแบบกำหนดเองrenderMessageText
(ฟังก์ชัน) - ข้อความข้อความที่กำหนดเองrenderMessageImage
(ฟังก์ชัน) - รูปภาพข้อความที่กำหนดเองrenderMessageVideo
(ฟังก์ชัน) - วิดีโอข้อความที่กำหนดเองimageProps
(Object) - อุปกรณ์ประกอบฉากพิเศษที่จะส่งผ่านไปยังส่วนประกอบ <Image>
ที่สร้างโดยค่าเริ่มต้น renderMessageImage
videoProps
(Object) - อุปกรณ์ประกอบฉากพิเศษที่จะส่งผ่านไปยังส่วนประกอบวิดีโอที่สร้างโดย renderMessageVideo
ที่จำเป็นlightboxProps
(Object) - อุปกรณ์ประกอบฉากพิเศษที่จะส่งไปยังไลท์บ็อกซ์ของ MessageImage
isCustomViewBottom
(Bool) - กำหนดว่า renderCustomView จะแสดงก่อนหรือหลังการดูข้อความ รูปภาพ และวิดีโอ ค่าเริ่มต้นเป็น false
renderCustomView
(ฟังก์ชัน) - มุมมองที่กำหนดเองภายในฟองอากาศrenderDay
(ฟังก์ชัน) - วันที่กำหนดเองเหนือข้อความrenderTime
(ฟังก์ชัน) - เวลาที่กำหนดเองภายในข้อความrenderFooter
(ฟังก์ชัน) - ส่วนประกอบส่วนท้ายแบบกำหนดเองบน ListView เช่น 'User is typing...'
; ดู App.tsx สำหรับตัวอย่าง แทนที่ตัวบ่งชี้การพิมพ์เริ่มต้นที่ทริกเกอร์เมื่อ isTyping
เป็นจริงrenderChatEmpty
(ฟังก์ชัน) - องค์ประกอบที่กำหนดเองเพื่อแสดงผลใน ListView เมื่อข้อความว่างเปล่าrenderChatFooter
(ฟังก์ชัน) - องค์ประกอบที่กำหนดเองเพื่อแสดงผลด้านล่าง MessageContainer (แยกจาก ListView)renderInputToolbar
(ฟังก์ชัน) - คอนเทนเนอร์ผู้แต่งข้อความแบบกำหนดเองrenderComposer
(ฟังก์ชั่น) - ผู้แต่งข้อความป้อนข้อความแบบกำหนดเองrenderActions
(ฟังก์ชัน) - ปุ่มการกระทำแบบกำหนดเองทางด้านซ้ายของผู้แต่งข้อความrenderSend
(ฟังก์ชัน) - ปุ่มส่งแบบกำหนดเอง คุณสามารถส่งลูกไปยังองค์ประกอบ Send
ดั้งเดิมได้ค่อนข้างง่าย เช่น การใช้ไอคอนที่กำหนดเอง (ตัวอย่าง)renderAccessory
(ฟังก์ชัน) - บรรทัดที่สองของการดำเนินการที่กำหนดเองด้านล่างผู้แต่งข้อความonPressActionButton
(ฟังก์ชัน) - โทรกลับเมื่อกดปุ่ม Action (หากตั้งค่าไว้ จะไม่ใช้ actionSheet
เริ่มต้น)bottomOffset
(จำนวนเต็ม) - ระยะห่างของการแชทจากด้านล่างของหน้าจอ (เช่น มีประโยชน์หากคุณแสดงแถบแท็บ)minInputToolbarHeight
(จำนวนเต็ม) - ความสูงขั้นต่ำของแถบเครื่องมืออินพุต ค่าเริ่มต้นคือ 44
listViewProps
(Object) - อุปกรณ์ประกอบฉากพิเศษที่จะส่งผ่านไปยังข้อความ <ListView>
; อุปกรณ์ประกอบฉากบางอย่างไม่สามารถแทนที่ได้ โปรดดูโค้ดใน MessageContainer.render()
เพื่อดูรายละเอียดtextInputProps
(Object) - อุปกรณ์ประกอบฉากพิเศษที่จะส่งไปยัง <TextInput>
textInputStyle
(Object) - สไตล์ที่กำหนดเองที่จะส่งไปยัง <TextInput>
multiline
(Bool) - ระบุว่าจะอนุญาตให้ <TextInput>
มีหลายบรรทัดหรือไม่ ค่าเริ่มต้น true
keyboardShouldPersistTaps
(Enum) - กำหนดว่าควรมองเห็นแป้นพิมพ์ต่อไปหลังจากการแตะหรือไม่ ดูเอกสาร <ScrollView>
onInputTextChanged
(ฟังก์ชัน) - โทรกลับเมื่อข้อความที่ป้อนเปลี่ยนแปลงmaxInputLength
(จำนวนเต็ม) - ความยาวอินพุตข้อความของผู้แต่งข้อความสูงสุดparsePatterns
(ฟังก์ชัน) - รูปแบบการแยกวิเคราะห์ที่กำหนดเองสำหรับข้อความแบบโต้ตอบแบบเนทีฟซึ่งใช้ในการลิงก์เนื้อหาข้อความ (เช่น URL และหมายเลขโทรศัพท์) เช่น: < GiftedChat
parsePatterns = { ( linkStyle ) => [
{ type : 'phone' , style : linkStyle , onPress : this . onPressPhoneNumber } ,
{ pattern : / #(w+) / , style : { ... linkStyle , styles . hashtag } , onPress : this . onPressHashtag } ,
] }
/>
extraData
(Object) - อุปกรณ์ประกอบฉากพิเศษสำหรับการแสดงผล FlatList อีกครั้งตามความต้องการ สิ่งนี้จะมีประโยชน์สำหรับการแสดงส่วนท้าย ฯลฯminComposerHeight
(Object) - กำหนดความสูงต่ำสุดของผู้แต่งmaxComposerHeight
(Object) - กำหนดความสูงสูงสุดของผู้แต่งเองscrollToBottom
(Bool) - เปิดใช้งานการเลื่อนไปที่ส่วนประกอบด้านล่าง (ค่าเริ่มต้นคือเท็จ)scrollToBottomComponent
(ฟังก์ชัน) - คอนเทนเนอร์เลื่อนไปยังส่วนประกอบด้านล่างแบบกำหนดเองscrollToBottomOffset
(จำนวนเต็ม) - ออฟเซ็ตความสูงที่กำหนดเองซึ่งจะเริ่มแสดง Scroll To Bottom Component (ค่าเริ่มต้นคือ 200)scrollToBottomStyle
(Object) - สไตล์ที่กำหนดเองสำหรับคอนเทนเนอร์ส่วนประกอบด้านล่างalignTop
(บูลีน) ควบคุมว่าฟองข้อความจะปรากฏที่ด้านบนของแชทหรือไม่ (ค่าเริ่มต้นคือเท็จ - ฟองอากาศจะอยู่ด้านล่าง)onQuickReply
(ฟังก์ชัน) - โทรกลับเมื่อส่งการตอบกลับอย่างรวดเร็ว (ไปยังเซิร์ฟเวอร์แบ็กเอนด์)renderQuickReplies
(ฟังก์ชัน) - ปรับแต่งมุมมองตอบกลับด่วนทั้งหมดquickReplyStyle
(StyleProp) - ปรับแต่งสไตล์มุมมองตอบกลับด่วนrenderQuickReplySend
(ฟังก์ชัน) - มุมมอง ส่ง ตอบกลับด่วนแบบกำหนดเองshouldUpdateMessage
(ฟังก์ชัน) - ให้คอมโพเนนต์ข้อความรู้ว่าเมื่อใดควรอัปเดตนอกกรณีปกติinfiniteScroll
(Bool) - เลื่อนขึ้นอย่างไม่สิ้นสุดเมื่อไปถึงด้านบนของคอนเทนเนอร์ข้อความ เรียกใช้ฟังก์ชัน onLoadEarlier โดยอัตโนมัติหากมีอยู่ (ยังไม่รองรับเว็บ) คุณต้องเพิ่มเสา loadEarlier
ด้วยisStatusBarTranslucentAndroid
(Bool) - หากคุณใช้แถบสถานะโปร่งแสงบน Android ให้ตั้งค่าตัวเลือกนี้เป็นจริง ถูกละเว้นบน iOS เสา messages
ควรทำงานนอกกรอบด้วย Redux ในกรณีส่วนใหญ่ นี่คือทั้งหมดที่คุณต้องการ
หากคุณตัดสินใจที่จะระบุเสา text
GiftedChat จะไม่จัดการสถานะ text
ภายในของตัวเองอีกต่อไป และจะเลื่อนไปที่เสาของคุณทั้งหมด นี่เป็นวิธีที่ยอดเยี่ยมสำหรับการใช้เครื่องมืออย่าง Redux แต่มีขั้นตอนพิเศษอีกขั้นตอนหนึ่งที่คุณต้องทำ: เพียงใช้ onInputTextChanged
เพื่อรับเหตุการณ์การพิมพ์และรีเซ็ตเหตุการณ์ (เช่น เพื่อล้างข้อความ onSend
):
< GiftedChat
text = { customText }
onInputTextChanged = { text => this . setCustomText ( text ) }
/* ... */
/>
หากคุณใช้ Create React Native App / Expo ก็ไม่จำเป็นต้องมีขั้นตอนการติดตั้งเฉพาะของ Android คุณสามารถข้ามส่วนนี้ได้ มิฉะนั้น เราขอแนะนำให้แก้ไขการกำหนดค่าโปรเจ็กต์ของคุณดังนี้
ตรวจสอบให้แน่ใจว่าคุณมี android:windowSoftInputMode="adjustResize"
ใน AndroidManifest.xml
ของคุณ :
< activity
android : name = " .MainActivity "
android : label = " @string/app_name "
android : windowSoftInputMode = " adjustResize "
android : configChanges = " keyboard|keyboardHidden|orientation|screenSize " >
สำหรับ Expo มีวิธีแก้ไขอย่างน้อย 2 วิธีในการแก้ไข:
KeyboardAvoidingView
หลังจาก GiftedChat สิ่งนี้ควรทำสำหรับ Android เท่านั้น เนื่องจาก KeyboardAvoidingView
อาจขัดแย้งกับการหลีกเลี่ยงแป้นพิมพ์ iOS ที่สร้างไว้ใน GiftedChat แล้ว เช่น: <View style={{ flex: 1 }}>
<GiftedChat />
{
Platform.OS === 'android' && <KeyboardAvoidingView behavior="padding" />
}
</View>
หากคุณใช้ React Navigation อาจจำเป็นต้องมีการจัดการเพิ่มเติมเพื่อคำนึงถึงส่วนหัวและแท็บการนำทาง คุณสมบัติ keyboardVerticalOffset
ของ KeyboardAvoidingView
สามารถตั้งค่าความสูงของส่วนหัวการนำทางและสามารถตั้งค่า tabBarOptions.keyboardHidesTabBar
เพื่อป้องกันไม่ให้แถบแท็บแสดงเมื่อแป้นพิมพ์เปิดขึ้น เนื่องจากข้อบกพร่องในการคำนวณความสูงบนโทรศัพท์ Android ที่มีรอยบาก จึงแนะนำให้ใช้ KeyboardAvoidingView
เหนือโซลูชันอื่นๆ ที่เกี่ยวข้องกับการคำนวณความสูงของหน้าต่าง
การเพิ่มแถบสถานะพื้นหลังทึบแสงบน app.json (แม้ว่า android:windowSoftInputMode="adjustResize"
จะถูกตั้งค่าภายในบนแอป Android ของ Expo แต่แถบสถานะโปร่งแสงทำให้ไม่ทำงาน): https://docs.expo.io/versions /latest/guides/configuration.html#androidstatusbar
หากคุณวางแผนที่จะใช้ GiftedChat
ภายใน Modal
ดูที่ #200
yarn global add expo-cli
yarn install
อ้างอิงexpo start
yarn global add expo-cli
yarn install
อ้างอิงexpo start -w
อัปเกรดเวอร์ชันของว่าง
yarn add -D react-app-rewired
touch config-overrides.js
module . exports = function override ( config , env ) {
config . module . rules . push ( {
test : / .js$ / ,
exclude : / node_modules[/\](?!react-native-gifted-chat|react-native-lightbox|react-native-parsed-text) / ,
use : {
loader : 'babel-loader' ,
options : {
babelrc : false ,
configFile : false ,
presets : [
[ '@babel/preset-env' , { useBuiltIns : 'usage' } ] ,
'@babel/preset-react' ,
] ,
plugins : [ '@babel/plugin-proposal-class-properties' ] ,
} ,
} ,
} )
return config
}
คุณจะพบตัวอย่างและ การสาธิตเว็บ ที่นี่: xcarpentier/gifted-chat-web-demo
อีกตัวอย่างหนึ่งของ Gatsby : xcarpentier/clean-archi-boilerplate
อย่าลังเลที่จะถามคำถามฉันบน Twitter @FaridSafi! หรือ @xcapetir!
กำลังมองหาผู้เชี่ยวชาญอิสระ ReactNative ที่มีประสบการณ์มากกว่า 14 ปีอยู่ใช่ไหม? ติดต่อ Xavier จากเว็บไซต์ของเขา!