我很反应原生,我正在开发一个聊天/论坛应用程序。最近,我在尝试为我的应用创建直接消息部分时遇到了一些麻烦。我不知道如何将我的数据库连接到我的前端。这是问题所在:
我使用的mongodb数据库包含两个集合:消息和对话。
每个会话都有一个唯一的ID,每条消息都有一个与其所属的会话对应的chatId。
在我的本机应用程序中,在Direct Message组件中,我有一个显示不同聊天的flatlist
。
当直接消息组件willMount()
我调用异步函数getChats()
时,它从当前用户所属的数据库中获取聊天。然后将获取的聊天设置为状态。
然后,在getChats()
内,在聊天设置为状态后,我有for loop
基本上遍历整个this.state.chats
数组,然后调用函数{{1}它获取与聊天ID共享相同chatIds的所有消息。然后,已获取的消息将添加到getMessages(this.state.chats[i].id)
。
最后,带有道具的this.state.messages
flatlist
,进行聊天。
我希望能够在聊天keyExtractor={(item)=>item._id}
data ={this.state.chats}
renderItem={({item})=>this._renderChats(item)}
extraData = {this.state}
中显示最新消息内容和发件人,但是,错误消息说消息内容未定义。
我认为这可能是由于消息未设置为呈现聊天之前的状态,但我不确定。
你会如何解决这个问题?你会改变前端还是后端?你会改变两者吗?我应该分享我的代码,以便更容易理解问题吗?
提前致谢。
答案 0 :(得分:0)
非常清楚地解释了这个问题!简而言之:
如何使用会话概述构建聊天页面(显示每个会话的最后一条消息) - 使用React Native,MongoDB,NodeJS和Express
一些说明:
chatId
重命名为conversationId
,将chats
重命名为conversations
尝试最小化互联网请求 - 因为它们资源密集且速度慢
conversations.count+1
个请求,可能只是1
extraData
字段query('currentUser.conversations { text, messages(limit 1), ... }')
例如。使用rest + mongoose:
// controller
// see https://stackoverflow.com/questions/32207457/node-js-mongoose-populate-limit
// populate the first item in conversation.messages
const conversations = ()=> db.Conversations
.find(...)
.populate({ path: 'messages', options: { limit: 1, sort: { created: -1} }}))
.exec(...)
// router
router.get('/conversations', ({user}, res)=>
getConversations({user})
.then(data=> res.send({data}))
.catch(error=> res.send({error}))
)
(这假设消息是对话中的虚拟属性)
// schema
const messageSchema = new Schema({
text: String, ...
conversationId: {type: Schema.ObjectId, ref: 'conversation'}
})
const conversationSchema = new Schema({
participants: [{type: Schema.ObjectId, ref: 'user'}]
})
// add a "virtual" field to conversation called messages
// https://stackoverflow.com/questions/43882577/mongoosejs-virtual-populate
conversationSchema.virtual('messages', {
ref: 'message',
localField: '_id',
foreignField: 'conversationId'
})
// make sure the "virtual" fields are included in conversion
conversationSchema.set('toObject', { virtuals: true });
conversationSchema.set('toJSON', { virtuals: true });
假设所有数据都已损坏;例如。如果消息数据丢失,应用程序不应该崩溃。在访问之前检查该属性是否存在,并在继续之前将其转换为预期的数据类型。
.catch
,请确保始终拥有.then
并记录错误,并将错误消息粘贴到问题中(如果有)。Uncaught TypeError: Cannot read property 'c' of undefined
,在执行a.b.c
时,您知道a
是一个对象,可以通过先检查来避免; if (a.b) use(a.b.c)
或短信:a.b && use(a.b.c)
ConversationsPage
已初始化,state.conversations
为空willMount
调用 - > fetchAllConversations
已启动,需要时间,异步willMount
结束 - >被render
调用 - >空列表呈现fetchAllConversations
'首次请求完成 - > setState{conversations}
- >再次调用render
- >呈现完整列表(在您的情况下,它因为丢失了最后一个消息字段而崩溃)fetchAllConversations
调用fetchMessagesForConversations
,它发出许多api请求,可能多次调用setState
(无效),这反过来会导致重新呈现不要忘记加载状态
state = {loading: false}
render () {
const {loading} = this.state
return <FlatList renderHeader={()=> loading? <ActivityIndicator .../>: null} .../>
}
相反,一个简单的修复将在加载所有消息后调用setState:
async fetchAllConversations () {
const conversations = await api.conversations()
await Promise.all(conversations.map(c=> c.messages = await api.messagesForConversationId(c._id)))
// similar to for (let i=0; i<conversations.length; i++) {
// const c = conversations[i]; c.messages = await api.messagesForConversationId(c._id)}
return conversations
}
async reload () {
this.setState({loading: true})
this.fetchAllConversations()
.then(conversations=> this.setState({conversations}))
.catch(showError)
// stop loading both on error and success
.then(()=> this.setState({loading: false}))
}
state = {loading: false, conversations: []}
willMount () { this.reload() }
虽然更好的解决方案将从上面替换fetchAllConversations
,假设使用服务器端上面提到的虚拟属性和人口:
async fetchAllConversationsIncludingLastMessage () {
const conversations = await api.conversationsWithLastMessage()
return conversations
}
这会减少流量:
ConversationsPage
已初始化,state.conversations
为空willMount
调用 - &gt; reload
已启动,需要时间,异步willMount
结束 - &gt;被render
调用 - &gt;加载指标呈现reload
唯一的请求完成 - &gt; setState{conversations}
- &gt;再次调用render
- &gt;完整列表呈现
附加说明:
docker
以简化服务器设置(即让mongodb + nodejs一起运行)db.Conversation.find({participants: {$includes: req.user._id}}) // pseudocode
mobx
,redux
,apollo
...)解决其中的一部分REST
,请制作一个api包装助手+看看mobx graphql
和apollo或类似的