【问题标题】:updateLastConsumedMessageIndex freezes causing no update in messagesupdateLastConsumedMessageIndex 冻结导致消息中没有更新
【发布时间】:2020-05-06 11:12:07
【问题描述】:

当组件被安装时,通道要么从现有的抓取,要么创建一个新的。此通道稍后会保存在组件中的持久性状态中。当组件被点击时,所有的频道消息都会被更新为消费。

代码属于“今日轮班频道”栏目。右侧代码是单独的。

Senario :当我单击用户 onTaskSelect 时,会在设置所有消耗的消息后触发右侧的整个用户聊天。这里 出现问题 1 和 2。现在我单击另一个用户,然后单击返回到以前单击的用户出现问题 3

问题:
1) 它不更新消费的消息并且总是返回零。
2) 它停止接收来自 joinOrCreate 函数中调用的 .on 侦听器的新消息。
3) 出现错误的重复点击响应
SyncError:禁止访问身份(状态:403,代码:54007) 在 mapTransportError (http://localhost:3000/static/js/0.chunk.js:162153:12) 在http://localhost:3000/static/js/0.chunk.js:162210:20

注意:频道只设置一次,除非页面刷新,否则永远不会离开
注意:右侧的整个聊天工作正常,并且位于单独的模块中。
注意:客户端在应用程序开始时被初始化为上下文,该上下文在应用程序从打开到关闭的整个生命周期中持续存在。

const TaskCard = props => {

    const [lastMessage, setLastMessage] = useState({})
    const [open, setOpen] = useState(false)
    const [unread, setUnread] = useState(0)
    const [channel, setChannel] = useState({})

    const joinOrCreate = useCallback(async() => {
        try{
            const fetchedChannel = await props.client.getChannelByUniqueName(props.task.id.toString())
            let joined = fetchedChannel
            if(fetchedChannel.state.status !== "joined") {
                joined = await fetchedChannel.join()
            }
            console.log()
            joined.getMessages()
            .then(messages => {
                if(messages.items.length > 0) {
                    if(joined.lastConsumedMessageIndex < messages.items.length - 1) {
                        setUnread(true)
                    }
                    const recent_message = messages.items[messages.items.length - 1]
                    const limit_message = recent_message.body.slice(0,14)
                    setLastMessage({
                        body: limit_message.length === 14? (limit_message + '...') : limit_message,
                        time: recent_message.timestamp,
                        index: recent_message.index,
                    })
                }
            })
            joined.on('messageAdded', messageUpdated)
            setChannel(joined)
        }
        catch(ch) {
            console.log(ch)
            try{
                const newChannel = await props.client.createChannel({
                    uniqueName: props.task.id.toString(),
                    friendlyName: 'General Chat Channel'
                })

                let joined = newChannel
                if(newChannel.state.status !== "joined") {   
                    joined = await newChannel.join()                 
                }
                joined.getMessages()
                .then(messages => {
                    if(messages.items.length > 0) {
                        const recent_message = messages.items[messages.items.length - 1]
                        setLastMessage({
                            body: recent_message.body,
                            time: recent_message.timestamp,
                        })
                    }
                })
                joined.on('messageAdded', messageUpdated)
                setChannel(joined)
            }

            catch(e) {
                console.log(e)
            }
        }
    }, [props.client, props.task.id])

    const messageUpdated = message => {
        const limit_message = message.body.slice(0,14)
        setLastMessage({
            body: limit_message.length === 14? (limit_message + '...') : limit_message,
            time: message.timestamp,
            index: message.index
        })
    }

    const onTaskSelect = () => {
        // console.log(lastMessage.index)
        console.log(channel.uniqueName)
        if(lastMessage.body) {
            channel.updateLastConsumedMessageIndex(+lastMessage.index)
            .then(res => {
                console.log(res)
            })
            .catch(e => {
                // console.log(props.client)
                // console.log(channel)
                console.log(e)
            })
        }
        props.onTaskClick(props.task.id.toString())
    }

    useEffect(() => {
        if(props.channelId === props.task.id) {
            setOpen(true)
            setUnread(false)
        }
        else {
            setOpen(false)
        }
    }, [props.channelId, props.task.id])

    useEffect(() => {
        joinOrCreate()
    }, [joinOrCreate])

    useEffect(() => {
        if(channel.lastConsumedMessageIndex < lastMessage.index && !open) {
            setUnread(true)
        }
    }, [channel.lastConsumedMessageIndex, lastMessage, open])

return (
        <Row key={props.task.id} >
            <Col className='justify-center'>
                <Card className={'more-than-90 ' + (open? 'background-active' : null)}
                    onClick={e => onTaskSelect()}
                >
                    <Row>
                        <Col md={2} style={{alignSelf: 'center', paddingLeft:'15px'}}>
                            {
                                props.task.worker.pic_url === "" || props.task.worker.pic_url === null ?
                                <div className="name-image">
                                    {props.task.worker.first_name[0] + props.task.worker.last_name[0]}
                                </div>
                                :
                                <Image width={50} height={50} src={props.task.worker.pic_url} roundedCircle />                                                
                            }
                        </Col>
                        <Col md={10}>
                            <Row>
                                <Col md={8}>
                                    <p style={{fontSize:'.9rem'}}>{props.task.worker.name}</p>
                                </Col>
                                <Col>
                                    <p style={{fontSize:'.7rem'}} className='left-align-text'>{lastMessage.time? moment(lastMessage.time).format('hh:mm A') : null}</p>
                                </Col>
                            </Row>
                            <Row>
                                <Col md={8}>
                                    <p style={{fontSize:'.7rem'}}>{lastMessage.body? lastMessage.body : null}</p>
                                </Col>
                                <Col>
                                    {
                                        unread ?
                                        <FontAwesomeIcon 
                                            icon={faEnvelopeOpenText}
                                            size="lg"
                                            color={"#0064bb"}
                                        />
                                        :
                                        null
                                    }
                                </Col>
                            </Row>
                        </Col>
                    </Row>
                </Card>
            </Col>
        </Row>
    )
}

【问题讨论】:

  • “它不更新消费的消息并且总是返回零”,你的意思是索引?假设您已经在服务上将“消息读取状态”设置为启用,您可能必须在通道中的第一条消息上设置初始索引 0,以便将通道的消耗报告传回 Twilio。完成后,Twilio 应该会为您正确更新索引。在我自己理解之前,我必须仔细阅读它:twilio.com/docs/chat/consumption-horizon

标签: reactjs twilio-programmable-chat twilio-javascript


【解决方案1】:

这里是 Twilio 开发者宣传员。

我认为 Will Sams 的评论很有道理。您确实需要设置一个未读索引以使通道开始,然后才能具有有效的未读索引。来自文档:

注意:聊天不会自动设置消费范围。如果您未在应用程序中明确设置此选项,则通道内的用户将不存在消费范围。如果没有消耗范围,您的用户的消耗范围(读取状态)将无法在客户端之间正确同步。 如果用户没有在频道上设置消费范围,则获取未消费的消息将始终返回 0。如果 Channel 的成员没有消费状态,则他们的最后消费索引和时间戳将为 null 或 0,具体取决于平台。

因此,在创建频道时,我会set the channel's messages to unconsumed 来启动该措施。您也可以use the function setAllMessagesConsumed,而不必阅读最后一条消息的索引。

我还注意到,当您设置最后一条消息时,您错过了在某一点设置其索引:

                        const recent_message = messages.items[messages.items.length - 1]
                        setLastMessage({
                            body: recent_message.body,
                            time: recent_message.timestamp,
                        })

这可能会造成麻烦。

我担心您的回调和效果的设置方式。当您触发 onTaskSelect 时,看起来好像您将任务 ID 发送回父级。

props.onTaskClick(props.task.id.toString());

大概是这样您就可以在主面板中看到所有消息。

但是,我还假设这会在父级中设置一个任务,然后将其作为 props.tasks 传递给该子级。 joinOrCreate 回调设置为在 props.task.id 更新时更新,useEffectjoinOrCreate 更改为前提。所以我的猜测是,每当您在任务之间进行更改时,都会触发joinOrCreate 的清理和重新评估。除了没有清理功能,所以你最终每次都为这些组件中的每一个重新加载通道。我猜这与中断事件以及再次单击时出现的最终错误有关。

相反,我可能会重新设计它,这样TaskCard 组件就不会控制通道对象的生命周期。我将加载并加入您打算在父组件中呈现的频道列表,然后将频道对象传递给TaskCard。这将简化组件,因为父级将处理数据,TaskCard 可以只处理渲染。这也意味着当卡片的状态发生变化(从显示到不显示)时,您只是重新渲染数据。这样,您还可以在TaskCard 和屏幕截图右侧的聊天视图之间共享频道对象(否则我猜您也必须在该组件中加载它,这可能也无济于事)。

这些只是基于我在您的应用程序中看到的一些想法。我希望他们有所帮助!

【讨论】:

    猜你喜欢
    • 2017-03-09
    • 1970-01-01
    • 1970-01-01
    • 2016-06-13
    • 2022-12-14
    • 2012-08-02
    • 1970-01-01
    • 1970-01-01
    • 2017-07-30
    相关资源
    最近更新 更多