React Native 및 웹을 위한 가장 완벽한 채팅 UI
데모 웹?
간식영재채팅놀이터
Farid Safi가 공동 창립한 파리 코딩 부트캠프
자세히 알아보려면 클릭하세요.
Go로 작성된 확장 가능한 채팅 API/서버
API 투어 | React 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:
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
가이드를 따르세요: 반응 네이티브 안전 영역 컨텍스트
가이드 따르기: 반응 네이티브 재활성화
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
참조하세요!
사용자 이름이 표시되고 모든 메시지가 왼쪽에 표시되는 Slack과 더 비슷하게 보이도록 기본 UI를 재정의하는 방법에 대한 예는 example/example-slack-message
의 파일을 참조하세요.
예: 채팅 메시지
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
}
예: 빠른 답장 옵션이 포함된 채팅 메시지
PR #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 ref) - 플랫리스트에 대한 참조textInputRef
(TextInput ref) - 텍스트 입력에 대한 참조messages
(Array) - 표시할 메시지isTyping
(Bool) - 타이핑 표시기 상태; 기본값은 false
. renderFooter
사용하면 이를 재정의합니다.text
(문자열) - 입력 텍스트입니다. 기본값은 undefined
지정하면 GiftedChat의 내부 상태가 무시됩니다(예: redux의 경우, 아래 참고 사항 참조).placeholder
(String) - text
비어 있는 경우의 자리 표시자입니다. 기본값은 'Type a message...'
입니다.messageIdGenerator
(함수) - 새 메시지에 대한 ID를 생성합니다. 기본값은 uuid에 의해 생성된 UUID v4입니다.user
(객체) - 메시지를 보내는 사용자: { _id, name, avatar }
onSend
(함수) - 메시지를 보낼 때 콜백alwaysShowSend
(Bool) - 입력 텍스트 작성기에 보내기 버튼을 항상 표시합니다. 기본값은 false
, 텍스트 입력이 비어 있지 않은 경우에만 표시됩니다.locale
(문자열) - 날짜를 현지화하는 로케일입니다. 먼저 필요한 로케일을 가져와야 합니다(예: 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인 경우 아바타는 같은 날 같은 사용자로부터 연속 메시지가 전송될 때만 표시됩니다. 기본값은 false
입니다onPressAvatar
(Function( user
)) - 메시지 아바타를 탭할 때의 콜백onLongPressAvatar
(Function( user
)) - 메시지 아바타를 길게 눌렀을 때의 콜백renderAvatarOnTop
(Bool) - 연속 메시지의 하단이 아닌 상단에 메시지 아바타를 렌더링합니다. 기본값은 false
입니다renderBubble
(함수) - 사용자 정의 메시지 풍선renderTicks
(Function( message
)) - 메시지 상태를 표시하는 사용자 정의 틱 표시기renderSystemMessage
(함수) - 사용자 정의 시스템 메시지onPress
(Function( context
, message
)) - 메시지 풍선을 눌렀을 때의 콜백onLongPress
(Function( context
, message
)) - 메시지 풍선을 길게 눌렀을 때의 콜백( showActionSheetWithOptions()
사용 예 참조)inverted
(Bool) - messages
표시 순서를 반대로 바꿉니다. 기본값은 true
입니다renderUsernameOnMessage
(Bool) - 메시지 풍선 안에 사용자의 사용자 이름을 표시할지 여부를 나타냅니다. 기본값은 false
입니다renderUsername
(함수) - 사용자 정의 사용자 이름 컨테이너renderMessage
(함수) - 사용자 정의 메시지 컨테이너renderMessageText
(함수) - 사용자 정의 메시지 텍스트renderMessageImage
(함수) - 사용자 정의 메시지 이미지renderMessageVideo
(함수) - 사용자 정의 메시지 비디오imageProps
(객체) - 기본 renderMessageImage
에 의해 생성된 <Image>
구성 요소에 전달될 추가 소품입니다.videoProps
(객체) - 필수 renderMessageVideo
에 의해 생성된 비디오 구성 요소에 전달될 추가 소품lightboxProps
(Object) - MessageImage
의 라이트박스에 전달될 추가 소품isCustomViewBottom
(Bool) - renderCustomView가 텍스트, 이미지 및 비디오 보기 이전 또는 이후에 표시되는지 여부를 결정합니다. 기본값은 false
입니다renderCustomView
(함수) - 버블 내부의 사용자 정의 보기renderDay
(함수) - 메시지 위의 사용자 정의 날짜renderTime
(함수) - 메시지 내 사용자 정의 시간renderFooter
(함수) - ListView의 사용자 정의 바닥글 구성 요소(예: 'User is typing...'
; 예제는 App.tsx를 참조하세요. isTyping
이 true일 때 트리거되는 기본 입력 표시기를 재정의합니다.renderChatEmpty
(함수) - 메시지가 비어 있을 때 ListView에서 렌더링할 사용자 정의 구성 요소renderChatFooter
(함수) - MessageContainer 아래에 렌더링할 사용자 정의 구성 요소(ListView와 별도)renderInputToolbar
(함수) - 사용자 정의 메시지 작성기 컨테이너renderComposer
(함수) - 사용자 정의 텍스트 입력 메시지 작성기renderActions
(함수) - 메시지 작성기 왼쪽에 있는 사용자 정의 작업 버튼renderSend
(기능) - 사용자 정의 보내기 버튼; 예를 들어 사용자 정의 아이콘을 사용하기 위해 원래 Send
구성 요소에 하위 항목을 아주 쉽게 전달할 수 있습니다.renderAccessory
(함수) - 메시지 작성기 아래에 있는 사용자 정의 두 번째 작업 줄onPressActionButton
(Function) - 액션 버튼을 눌렀을 때 콜백(설정된 경우 기본 actionSheet
사용되지 않음)bottomOffset
(정수) - 화면 하단에서 채팅까지의 거리(예: 탭 표시줄을 표시하는 경우 유용함)minInputToolbarHeight
(Integer) - 입력 도구 모음의 최소 높이입니다. 기본값은 44
입니다.listViewProps
(Object) - <ListView>
메시지에 전달될 추가 소품입니다. 일부 props는 재정의될 수 없습니다. 자세한 내용은 MessageContainer.render()
의 코드를 참조하세요.textInputProps
(Object) - <TextInput>
에 전달될 추가 소품textInputStyle
(Object) - <TextInput>
에 전달될 사용자 정의 스타일multiline
(Bool) - <TextInput>
이 여러 줄이 되도록 허용할지 여부를 나타냅니다. 기본값은 true
.keyboardShouldPersistTaps
(Enum) - 탭 후 키보드가 계속 표시되어야 하는지 여부를 결정합니다. <ScrollView>
문서 참조onInputTextChanged
(함수) - 입력 텍스트가 변경될 때 콜백maxInputLength
(Integer) - 최대 메시지 작성기 TextInput 길이parsePatterns
(함수) - 메시지 콘텐츠(예: URL 및 전화번호)를 연결하는 데 사용되는 반응 네이티브 구문 분석 텍스트에 대한 사용자 정의 구문 분석 패턴입니다. 예: < GiftedChat
parsePatterns = { ( linkStyle ) => [
{ type : 'phone' , style : linkStyle , onPress : this . onPressPhoneNumber } ,
{ pattern : / #(w+) / , style : { ... linkStyle , styles . hashtag } , onPress : this . onPressHashtag } ,
] }
/>
extraData
(객체) - 요청 시 FlatList를 다시 렌더링하기 위한 추가 소품입니다. 이는 바닥글 등을 렌더링하는 데 유용합니다.minComposerHeight
(객체) - 작곡가의 사용자 정의 최소 높이입니다.maxComposerHeight
(Object) - 작곡가의 사용자 정의 최대 높이입니다.scrollToBottom
(Bool) - 아래쪽 구성 요소로 스크롤을 활성화합니다(기본값은 false).scrollToBottomComponent
(함수) - 하단 구성 요소 컨테이너로 사용자 정의 스크롤scrollToBottomOffset
(정수) - 아래쪽 구성 요소로 스크롤 표시를 시작하는 사용자 정의 높이 오프셋(기본값은 200)scrollToBottomStyle
(객체) - 하단 구성 요소 컨테이너의 사용자 정의 스타일alignTop
(Boolean) 메시지 풍선이 채팅 상단에 표시되는지 여부를 제어합니다. (기본값은 false - 거품이 하단에 정렬됨)onQuickReply
(함수) - 빠른 응답을 보낼 때의 콜백(백엔드 서버로)renderQuickReplies
(함수) - 모든 빠른 응답 보기 사용자 정의quickReplyStyle
(StyleProp) - 사용자 정의 빠른 답장 보기 스타일renderQuickReplySend
(함수) - 사용자 정의 빠른 답장 보내기 보기shouldUpdateMessage
(함수) - 메시지 구성 요소에 일반적인 경우가 아닌 경우 업데이트 시기를 알려줍니다.infiniteScroll
(Bool) - 메시지 컨테이너 상단에 도달하면 위로 무한 스크롤하고, 존재하는 경우 자동으로 onLoadEarlier 함수를 호출합니다(아직 웹에서는 지원되지 않음). loadEarlier
소품도 추가해야 합니다.isStatusBarTranslucentAndroid
(Bool) - Android에서 반투명 상태 표시줄을 사용하는 경우 이 옵션을 true로 설정합니다. iOS에서는 무시됩니다. messages
prop은 Redux와 함께 기본적으로 작동해야 합니다. 대부분의 경우 이것이 필요한 전부입니다.
text
소품을 지정하기로 결정한 경우 GiftedChat은 더 이상 자체 내부 text
상태를 관리하지 않고 전적으로 귀하의 소품에 따릅니다. 이는 Redux와 같은 도구를 사용하는 데 적합하지만 한 가지 추가 단계를 수행해야 합니다. 입력 이벤트를 수신하고 이벤트를 재설정하려면(예: onSend
텍스트 지우기) onInputTextChanged
구현하기만 하면 됩니다.
< GiftedChat
text = { customText }
onInputTextChanged = { text => this . setCustomText ( text ) }
/* ... */
/>
Create React Native App / Expo를 사용하는 경우 Android 관련 설치 단계가 필요하지 않습니다. 이 섹션을 건너뛸 수 있습니다. 그렇지 않은 경우에는 다음과 같이 프로젝트 구성을 수정하는 것이 좋습니다.
AndroidManifest.xml
에 android:windowSoftInputMode="adjustResize"
있는지 확인하세요.
< activity
android : name = " .MainActivity "
android : label = " @string/app_name "
android : windowSoftInputMode = " adjustResize "
android : configChanges = " keyboard|keyboardHidden|orientation|screenSize " >
Expo 의 경우 이를 해결할 수 있는 솔루션이 최소한 2개 있습니다.
KeyboardAvoidingView
추가합니다. KeyboardAvoidingView
GiftedChat에 이미 내장된 iOS 키보드 회피와 충돌할 수 있으므로 Android에서만 수행해야 합니다. 예: <View style={{ flex: 1 }}>
<GiftedChat />
{
Platform.OS === 'android' && <KeyboardAvoidingView behavior="padding" />
}
</View>
React Navigation을 사용하는 경우 탐색 헤더 및 탭을 고려하기 위해 추가 처리가 필요할 수 있습니다. KeyboardAvoidingView
의 keyboardVerticalOffset
속성은 탐색 헤더의 높이로 설정될 수 있으며 tabBarOptions.keyboardHidesTabBar
키보드가 켜져 있을 때 탭 표시줄이 표시되지 않도록 설정할 수 있습니다. 노치가 있는 Android 휴대폰의 높이 계산 관련 버그로 인해 창 높이 계산과 관련된 다른 솔루션보다 KeyboardAvoidingView
가 권장됩니다.
app.json에 불투명한 배경 상태 표시줄 추가( android:windowSoftInputMode="adjustResize"
Expo의 Android 앱에 내부적으로 설정되어 있어도 반투명 상태 표시줄로 인해 작동하지 않음): https://docs.expo.io/versions /latest/guides/configuration.html#androidstatusbar
Modal
내에서 GiftedChat
사용하려는 경우 #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!
14년 이상의 경험을 가진 ReactNative 프리랜서 전문가를 찾고 계십니까? Xavier 웹사이트에서 Xavier에게 문의하세요!