You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord.js机器人多Help命令按钮交互异常问题求助

Discord机器人Help命令多实例交互异常问题

问题现象:调用两次及以上Help命令时,仅最后一次调用的命令能正确处理按钮交互,其余命令的交互均出现异常。Help命令通过StringSelectMenu划分多个子菜单,每个子菜单包含同一类命令的若干分页内容。

问题示例

  • 两次调用/help命令后,操作第一个命令的按钮:进入子菜单最后一页时,"Next"和"Last"按钮未按预期禁用;返回第一页时也存在类似异常。但最后一次调用的命令功能完全正常。

问题原因分析

currentPage为静态共享变量,当第二次调用命令时,只有第二个命令实例能更新currentPage的值,所有命令实例共享同一个currentPage,导致之前的命令被迫使用最后一个实例的currentPage值,引发分页索引异常。

预期行为

  • 用户选择新子菜单时,自动禁用"First"和"Previous"按钮;若子菜单有多页,则启用"Next"和"Last"按钮,否则禁用所有按钮
  • 用户进入子菜单最后一页时,自动禁用"Next"和"Last"按钮
  • 用户回到子菜单第一页时,自动禁用"Previous"和"First"按钮
  • 用户处于中间页时,所有按钮均启用

已尝试方案

  • 基于interaction.id为每个按钮创建唯一ID
  • 打印currentPage值以追踪其变化
  • 检查按钮状态更新逻辑
  • 查找他人解决方案但无效
  • 创建会话为用户分配独立的currentPage实例
  • 使用立即执行函数表达式(IIFE)限制作用域

核心代码片段

以下是按钮交互与分页索引更新的核心代码:

// Handling received interactions from the collector
collector.on("collect", async (i) => {
    if (i.user.id == interaction.user.id) {
        // If the interaction received is not from the buttons nor from the select menu, do nothing.
        if (!i.isButton() && !i.isStringSelectMenu()) return;
        // Defer the reply since the command takes longer time than usual to complete
        await i.deferUpdate();
        // Button handling starts here
        if (i.isButton()) {
            // If the user is still on the starting menu, disable all the buttons
            if (currentCategory == menu.init) {
                for (const i of buttons) {
                    await i.setDisabled(true);
                }
                // User is not on the starting menu
            } else {
                // Update the page according to the interaction of the user
                switch (i.customId) {
                    case "previous":
                        currentPage -= 1;
                        break;
                    case "next":
                        currentPage += 1;
                        break;
                    case "first":
                        currentPage = 0;
                        break;
                    case "last":
                        currentPage = currentCategory.length - 1;
                        break;
                    default:
                        handleError(
                            i,
                            "Unknown button interaction."
                        );
                }

                // Disabled and enable certain buttons to avoid errors
                // First page
                if (currentPage == 0) {
                    await previousBtn.setDisabled(true);
                    await firstBtn.setDisabled(true);
                    // Re-enable in case disabled
                    await nextBtn.setDisabled(false);
                    await lastBtn.setDisabled(false);
                    // Last page
                } else if (
                    currentPage ==
                    currentCategory.length - 1
                ) {
                    await nextBtn.setDisabled(true);
                    await lastBtn.setDisabled(true);
                    // Re-enable in case disabled
                    await previousBtn.setDisabled(false);
                    await firstBtn.setDisabled(false);
                    // Middle pages
                } else {
                    // Reenable all buttons in case disabled
                    for (const button of buttons) {
                        await button.setDisabled(false);
                    }
                }

                console.log("BTN:", currentPage);

                // Update the embed message;
                await i.editReply({
                    embeds: [currentCategory[currentPage]],
                    components: [selectMenuRow, buttonsRow],
                });
            }
            // Select Menu Handling
        } else if (i.isStringSelectMenu()) {
            // i.values[0] is the command category that the user had chosen
            switch (i.values[0]) {
                case "fun":
                    currentCategory = menu.fun;
                    break;
                case "utils":
                    currentCategory = menu.utilities;
                    break;
                case "welcomebye":
                    currentCategory = menu.welcome_goodbye;
                    break;
                default:
                    currentCategory = menu.init;
                    break;
            }
            currentPage = 0; // Reset the page number
            // Disable the previous and next buttons to avoid unexpected interactions
            await firstBtn.setDisabled(true);
            await previousBtn.setDisabled(true);
            // If there are more than one page of help in that category, allow the user to move on the next pages
            if (currentCategory.length > 1) {
                await nextBtn.setDisabled(false);
                await lastBtn.setDisabled(false);
                // If there is only one page of help, disable all the buttons to prevent causing errors
            } else {
                await nextBtn.setDisabled(true);
                await lastBtn.setDisabled(true);
            }
            await interaction.editReply({
                embeds: [currentCategory[currentPage]],
                components: [selectMenuRow, buttonsRow],
            });
        }
        // A non-command-caller user tries to interact with the command
    } else {
        await i.deferUpdate();
        await i.followUp({
            content: `This is not for you.`,
            ephemeral: true,
        });
    }
});

内容的提问来源于stack exchange,提问作者TommyYOyoyo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 09:22:19