【问题标题】:Fetch unread messages from PubNub and render notifications从 PubNub 获取未读消息并呈现通知
【发布时间】:2021-12-07 19:15:20
【问题描述】:

我正在尝试从 PubNub 获取未读消息。流程是这样的:

  1. 设置授权
  2. 获取频道元数据
  3. 获取未读消息等...

我没有运气按顺序运行这些功能。那一个是在前一个完成之后执行的。

async function setGrant(){
     await pubnub.grant(
        {
            channels: [userId.toString() + '.*'],
            ttl: 55,
            read: true,
            write: true,
            update: true,
            get: true,
        },(status) => {
         return new Promise(function (resolve) {
             resolve(status)
     });
    });
}

 async function getMetadata() {
     await pubnub.objects.getAllChannelMetadata(
        {
            include: {
                customFields: true
            }
        }).then((res: any) => {
        return new Promise(function (resolve) {
            resolve(setChannelMetadata(res.data));
        });
    });
}


 async function getUnreadedMessages() {
     await pubnub.messageCounts({
        channels: channels,
        channelTimetokens: tokens,
    }).then((res: any) => {
        console.log(res);
        return new Promise(function (resolve) {
            resolve(setUnreadMessage(res));
        });
    });
}


async function setChannelsAndTokens(){
    channelMetadata.forEach((value, index) => {
        tokens.push(value.custom.lastToken);
        channels.push(value.id)
    });

    return new Promise(function (resolve) {
        getUnreadedMessages()
        resolve("Chanells and tokens set!");
    })
}

function getUnreadMessagesProccess() {
    return setGrant().then(getMetadata).then(setChannelsAndTokens).then(getUnreadedMessages)
}

编辑:

看起来这也是渲染的问题。当我收到getUnreadedMessages() 然后我正在编辑对象客户端:

clients.forEach((value, index) => {
       if (res.channels[value.id + '-' + userId + '-chat']) {
           value.unreadMessages = res["channels"][value.id + '-' + userId + '-chat'];
        } else {
            value.unreadMessages = 0;
        }
      console.log("UNREAD MESSAGE", value.unreadMessages, value.username);
});

基于此,我正在设置 showIcon:

<ClientItem
   client={item.item}
   isAdmin={isAdmin}
   navigation={navigation}
   fromAdminTab={fromAdminTab}
   showIcon={item.item.unreadMessages>0}
/>

但是这个图标显示不正确。

客户列表:

 import Colors from '@helper/Colors';
    import { useSelector } from '@redux/index';
    import { HealthierLifeOption } from '@redux/types';
    import React, { useEffect, useState } from 'react';
    import { View, Text, FlatList, ActivityIndicator } from 'react-native';
    import ClientItem from './ClientItem';
    import {usePubNub} from "pubnub-react";
    
    export type Client = {
        id: number;
        username: string;
        individualPlanPaid: boolean;
        healthierLifeOption?: HealthierLifeOption;
        company?: {
          id: number;
          companyName: string;
        };
        mentor?: {
          id: number;
          username: string;
        };
    }
    
    type Props = {
        navigation: any;
        clients: Client[];
        isAdmin?: boolean;
        isLoading: boolean;
        onEndReached: Function;
        fromAdminTab?: boolean
    }
    
    const ClientList = ({ navigation, clients, onEndReached, isLoading, isAdmin = false, fromAdminTab= false }: Props) => {
        const resultCount = useSelector(state => state.user.menteesResultCount);
        const [hasMoreResults, setHasMoreResults] = useState(true);
        const userId = useSelector(state => state.user.id);
        const pubnub = usePubNub();
    
        useEffect(() => {
    
            getUnreadMessagesProccess
          setHasMoreResults(resultCount !== clients?.length);
    
        }, [resultCount, clients]);
    
    
        async function setGrant() {
            return new Promise( async resolve => {
                await pubnub.grant({
                    channels: [
                        '100-68-chat',
                        '101-68-chat',
                        '22-2-chat',
                        '22-96-chat',
                        '73-68-chat',
                        '78-68-chat',
                        '79-68-chat',
                        '81-68-chat',
                        '90-68-chat',
                        '92-68-chat',
                        '93-68-chat',
                        '98-68-chat',
                        '99-68-chat' ],
                    ttl: 55,
                    read: true,
                    write: true,
                    update: true,
                    get: true,
                }, response => resolve(response));
            });
        }
    
        async function getMetadata() {
            const options = {include: {customFields: true}};
            return await pubnub.objects.getAllChannelMetadata(options);
        }
    
        function setChannelsAndTokens(channelMetadata, channels, tokens) {
    
            channelMetadata.data.forEach((value, index) => {
                tokens.push(value.custom.lastToken);
                channels.push(value.id.toString())
            });
        }
    
        async function getUnreadedMessages(channels, tokens) {
            return new Promise(async resolve => {
                pubnub.messageCounts({
                    channels: null,
                    channelTimetokens: tokens,
                }).then(res => {
                    clients.forEach((value, index) => {
                        if (res.channels[value.id + '-' + userId + '-chat']) {
                            value.unreadMessages = res["channels"][value.id + '-' + userId + '-chat'];
                        } else {
                            value.unreadMessages = 0;
                        }
                        console.log("UNREAD MESSAGE", value.unreadMessages, value.username);
                    });
                    resolve()
                })
                    .catch(error => resolve(error));
            });
        }
    
        async function getUnreadMessagesProccess() {
            const tokens = ['1000'];
            const channels = ['1234567'];
            const userId = 1234567;
    
            const auth = await setGrant(userId);
            log([{statusCode: auth.statusCode}]);
    
            const channelMetadata = await getMetadata();
            log([channelMetadata,channels,tokens]);
    
            setChannelsAndTokens(channelMetadata, channels, tokens);
            const unread = await getUnreadedMessages(channels, tokens);
            log([unread]);
    
            return unread;
        }
    
    
        return (
            <View>
                <FlatList
                    keyExtractor={item => item.id.toString()}
                    data={clients}
                    onEndReached={() => hasMoreResults ? onEndReached() : null}
                    onEndReachedThreshold={0.4}
                    renderItem={item => (
                        <ClientItem
                            client={item.item}
                            isAdmin={isAdmin}
                            navigation={navigation}
                            fromAdminTab={fromAdminTab}
                            showIcon={parseInt(item.item.unreadMessages) > 0 }
                        />
                    )}
                    ListFooterComponent={isLoading
                      ? () => (
                          <View style={{ padding: 20 }}>
                            <ActivityIndicator animating size="large" color={Colors.border_gray} />
                          </View>
                        )
                      : null
                    }
                />
            </View>
        );
    }
    export default ClientList;

客户项目:

import React, {useEffect, useState} from 'react';
    import { Text, View, Image, TouchableOpacity } from 'react-native';
    import Images from '@helper/Images';
    import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
    import Colors from '@helper/Colors';
    import styles from '../styles';
    import ClientModal from './ClientModal/ClientModal';
    import { Client } from './ClientList';
    import { HealthierLifeOption } from '@redux/types';
    
    type Props = {
        client: Client;
        navigation: any;
        isAdmin?: boolean;
        fromAdminTab?: boolean;
        showIcon?: boolean
    }
    
    const ClientItem = ({ client, navigation, isAdmin = false, fromAdminTab= false, showIcon= false }: Props) => {
        const [showModal, setShowModal] = useState(false);
    
        console.log(showIcon); // its not passed correclty
    
        let clientIcon = Images.icon.logoIconOrange 
    
        const handleContinueButton = () => {
            if(!fromAdminTab) {
                navigation.navigate('ChatFromClientsList', { selectedId: client.id, showBackButton: true });
            }else {
                setShowModal(!showModal)
            }
        };
    
        return (
            <View style={styles.client_item_container}>
            

<TouchableOpacity style={styles.client_content_container} onPress={handleContinueButton}
                >
                <View style={styles.image_container}>
                    <Image
                        style={styles.client_profile_img}
                        source={clientIcon}
                        resizeMode="contain"
                        resizeMethod="resize"
                    />
                </View>
                <View style={styles.title_container}>
                    <Text style={styles.title} >{ client.username } </Text>
                </View>
                <View style={styles.dot_container}>
                {showIcon  &&  <FontAwesome5
                    name="comment-dots"
                    size={20}
                    color={Colors.red}

                />  }
                </View>
                <View style={styles.hamburger_container} >
                    <FontAwesome5
                        name="bars"
                        size={30}
                        color={Colors.black}
                        onPress={() => setShowModal(!showModal)}
                    />
                </View>
                <View>
                    <ClientModal
                        isVisible={showModal}
                        onCollapse={(value: boolean) => setShowModal(value)}
                        closeModal={(value: boolean) => setShowModal(value)}
                        client={client}
                        navigation={navigation}
                        isAdmin={isAdmin}
                    />
                </View>
            </TouchableOpacity>
        </View>
    );
};
export default ClientItem;

我不确定是因为从 Pubnub 获取数据还是因为渲染或我在 foreach 中处理数据的方式。

【问题讨论】:

    标签: javascript react-native async-await pubnub


    【解决方案1】:

    上一个完成后运行函数

    在经验编码风格中使用asyncawait。这有助于组织代码。使代码易于阅读。这也有助于操作顺序。

    我们所做的是在每个函数的awaitpromise 前面添加一个return。这允许我们在每个函数执行完成后分配结果变量,同时在编写代码时保留执行顺序。

    ? 注意:当 SDK 初始化为 secretKey 时,无需授予自己访问资源的权限。只需使用任何方法,就好像您已经拥有权限一样。 SDK 将使用您的密钥自动签署所有请求。

    按下代码 sn-p 下方的 Run code snippet 按钮进行测试。

    (async ()=>{
    'use strict';
    
    const publishKey   = "pub-c-51f1008b-7ddf-42b7-aec9-2d0153b0e766";
    const subscribeKey = "sub-c-1597b696-05af-11e6-a6dc-02ee2ddab7fe";
    const secretKey    = "sec-c-YTVjYjUzMWMtM2MxZC00YzdiLWE0ZjAtNWRmMWVmYmNkZGNl";
    const myUUID       = "myUniqueUUID"
    
    const pubnub = new PubNub({
        publishKey   : publishKey,
        subscribeKey : subscribeKey,
        secretKey    : secretKey,
        uuid         : myUUID,
    });
    
    const unread = await getUnreadMessagesProccess();
    
    async function getUnreadMessagesProccess() {
        const tokens = ['1000'];      // placeholder change me
        const channels = ['1234567']; // placeholder change me
        const userId = 1234567;       // placeholder change me
    
        const auth = await setGrant(userId);
        log([{statusCode: auth.statusCode}]);
    
        const channelMetadata = await getMetadata();
        log([channelMetadata,channels,tokens]);
    
        setChannelsAndTokens(channelMetadata, channels, tokens);
        const unread = await getUnreadedMessages(channels, tokens);
        log([unread]);
    
        return unread;
    }
    
    async function setGrant(userId) {
        return new Promise( async resolve => {
            await pubnub.grant({
                channels: [userId.toString() + '.*'],
                ttl: 55,
                read: true,
                write: true,
                update: true,
                get: true,
            }, response => resolve(response));
        });
    }
    
    async function getMetadata() {
        const options = {include: {customFields: true}};
        return await pubnub.objects.getAllChannelMetadata(options);
    }
    
    function setChannelsAndTokens(channelMetadata, channels, tokens) {
        channelMetadata.data.forEach((value, index) => {
            tokens.push(value.custom.lastToken);
            channels.push(value.id)
        });
    }
    
    async function getUnreadedMessages(channels, tokens) {
        try {
            return await pubnub.messageCounts({
                channels: channels,
                channelTimetokens: tokens,
            });
        }
        catch(error) {
            return error;
        }
    }
    
    async function getUnreadedMessagesAlternative(channels, tokens) {
        return new Promise(async resolve => {
            pubnub.messageCounts({
                channels: channels,
                channelTimetokens: tokens,
            }).then(result => resolve(result))
              .catch(error => resolve(error));
        });
    }
    
    function log(data) {
        // console.log(data);
        document.querySelector("#out").innerHTML += 
          `<div>${JSON.stringify(data)}</div>`;
    }
    
    })();
    <div id="out"></div>
    <script src="https://cdn.pubnub.com/sdk/javascript/pubnub.4.33.0.js"></script>

    【讨论】:

    • 您好,感谢您的解决方案。但是,如果例如调用 pubnub.messageCounts 失败,我将无法获取我的数据。如何处理?
    • 嗨@user2994290 好问题。我将在今天晚些时候更新答案。我将发布我最喜欢的 try/catch with async/await 方法。同时这里有一些描述各种选项的帖子:stackoverflow.com/a/40886720/524733itnext.io/error-handling-with-async-await-in-js-26c3f20bc06a
    • @user2994290 已添加!我发现有两个例子很有用。检查上面代码 sn-p 中的 getUnreadedMessagesgetUnreadedMessagesAlternative 方法。两者的工作方式几乎相同。
    • 感谢您的帮助,对我来说很遗憾,它不起作用。我只是更新我的问题。
    • 嗨@user2994290 看起来原来的问题已经改变了。最初发布的问题是关于asyncawait 编码模式以确保排序。您发布的新问题是用于 GUI 调试。我们上面提供的答案向您展示了如何修复函数排序。但是我们的代码使用占位符名称。您已将代码按原样放入无法运行的应用程序中。您需要将这些占位符值更改为使用您的真实频道名称。另外一个很好的资源可能是与 support@pubnub.com 联系以进行进一步的详细调试。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-04
    相关资源
    最近更新 更多