0

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

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

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

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

在此处输入图像描述

4

1 回答 1

1

Twilio 开发人员布道者在这里。

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

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

因此,在创建频道时,我会将频道的消息设置为未使用以启动该措施。您也可以使用该函数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,并且useEffect基于joinOrCreate更改。所以我的猜测是,每当您在任务之间进行更改时,都会触发清理和重新评估joinOrCreate. 除了没有清理功能,所以你最终每次都为这些组件中的每一个重新加载通道。我猜想这与破坏事件以及再次单击时出现的最终错误有关。

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

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

于 2020-05-07T03:47:15.957 回答