Discord.js:实现消息反应与Embed编辑的10秒持续交互
I'm building a Discord bot that fetches Urban Dictionary definitions. The intended behavior is that after triggering the command, users can click left/right arrows to cycle through definitions for 10 seconds. Right now, though, it only works for one switch—after that, no more interaction is possible.
Here's my current code:
async execute(message, args) { // if (!message.channel.nsfw) return message.channel.send("You can only send messages in a NSFW marked channel.") let worder = args[0]; if (!worder) return message.channel.send("Specify a word") let defin = await ud.all(args.join(' ')).catch(e => { message.channel.send("Word not found") return; }); message.channel.send({ embed: generateEmbed(defin, 0) }).then(async message => { if (defin.length < 1) return await message.react("➡️") const filter = (reaction, user) => { return ['⬅️', '➡️'].includes(reaction.emoji.name) }; message.awaitReactions(filter, { time: 1000 }).then(collected => { const reaction = collected.first(); let currentIndex = 0 message.reactions.removeAll().then(async() => { reaction.emoji.name === '⬅️' ? currentIndex -= 1 : currentIndex += 1 console.log(currentIndex) message.edit(generateEmbed(defin, currentIndex)) if (currentIndex !== 0) await message.react('⬅️') console.log(currentIndex, defin.length) if (currentIndex + 1 < defin.length) await message.react('➡️') }) }); }); }
Got it, let's fix this reaction switching issue. The core problems with your current code are that it only listens for one reaction, resets the index every time, and has a too-short timeout. Here's how to make repeated switches work within the 10-second window:
async execute(message, args) { // if (!message.channel.nsfw) return message.channel.send("You can only send messages in a NSFW marked channel.") let worder = args[0]; if (!worder) return message.channel.send("Specify a word"); let defin = await ud.all(args.join(' ')).catch(e => { message.channel.send("Word not found"); return; }); // Exit early if no definitions exist if (!defin || defin.length < 1) return; // Send the initial embed with the first definition const sentMessage = await message.channel.send({ embed: generateEmbed(defin, 0) }); // Add initial reaction only if there are multiple definitions if (defin.length > 1) { await sentMessage.react("➡️"); } let currentIndex = 0; const filter = (reaction, user) => { // Only listen to the command sender and valid arrow reactions return ['⬅️', '➡️'].includes(reaction.emoji.name) && user.id === message.author.id; }; // Create a collector that listens for reactions for 10 seconds const collector = sentMessage.createReactionCollector({ filter, time: 10000 }); collector.on('collect', async (reaction, user) => { // Remove the user's reaction to keep the message clean await reaction.users.remove(user); // Update index with boundary checks to avoid invalid positions if (reaction.emoji.name === '⬅️' && currentIndex > 0) { currentIndex--; } else if (reaction.emoji.name === '➡️' && currentIndex < defin.length - 1) { currentIndex++; } // Update the embed with the new definition await sentMessage.edit({ embed: generateEmbed(defin, currentIndex) }); // Clear existing reactions before adding new ones await sentMessage.reactions.removeAll(); // Add back appropriate arrows based on current position if (currentIndex > 0) { await sentMessage.react("⬅️"); } if (currentIndex < defin.length - 1) { await sentMessage.react("➡️"); } }); // Optional: Clean up reactions when the collector times out collector.on('end', () => { sentMessage.reactions.removeAll().catch(console.error); }); }
Key Fixes Explained:
- Persistent Listener: Switched from
awaitReactionstocreateReactionCollector—this keeps listening for reactions until the 10-second timeout, allowing multiple switches. - Retained Index: Moved
currentIndexoutside the reaction handler so it doesn't reset to 0 every time someone clicks an arrow. - User Restriction: Added a check to only respond to the user who triggered the command (prevents random users from messing with the navigation).
- Boundary Protection: Ensured the index can't go below 0 or above the last definition's position.
- Reaction Cleanup: Removed the user's reaction after processing, and only show arrows when they're useful (no left arrow on the first definition, no right arrow on the last).
- Fixed Timeout: Changed
time: 1000totime: 10000to match your 10-second requirement.
Now users can cycle back and forth through definitions as many times as they want within the 10-second window after running the command.
内容的提问来源于stack exchange,提问作者amrita

