Я пытаюсь запустить функцию настройки один раз, когда загружается действие Discord (https://discord.com/developers/docs/activities/how-activities-work).
Мой код каким-то образом запускает функцию дважды и создает ошибку.
Вот код, который я использую:
function App() {
const [auth, setAuth] = useState<authType>(null);
async function setupDiscordSdk() {
const CLIENT_ID = "my client id";
const discordSdk = new DiscordSDK(CLIENT_ID, { disableConsoleLogOverride: true });
await discordSdk.ready();
console.warn('DISCORD SDK READY!') // This somehow calls twice
// Authorize with Discord Client
const { code } = await discordSdk.commands.authorize({
client_id: CLIENT_ID,
response_type: "code",
state: "",
prompt: "none",
scope: [
"identify",
],
});
// Retrieve an access_token from your activity's server
const response = await fetch("/api/token", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
code,
}),
});
const { access_token, publicProfile, authkey } = await response.json();
localStorage.setItem('bread:authkey', authkey);
// Authenticate with Discord client (using the access_token)
let auth = (await discordSdk.commands.authenticate({
access_token,
}) as authTypeNOTNULL);
auth.publicProfile = publicProfile as boolean;
auth.user.avatarURL = (auth.user.avatar ? `https://cdn.discordapp.com/avatars/${auth.user.id}/${auth.user.avatar}.png?size=256` : `https://cdn.discordapp.com/embed/avatars/${(BigInt(auth.user.id) >> 22n) % 6n}.png`);
auth.discordSdk = discordSdk;
setAuth(auth);
console.warn('AUTHED SUCCESSFULLY.');
};
async function openLink(url: string) {
console.warn('Trying to open URL', url);
console.info(auth)
if (!auth) return console.error('Not authed');
return await auth.discordSdk.commands.openExternalLink({ url });
};
useEffect(() => console.info(auth), [auth]);
useEffect(() => {
setupDiscordSdk().catch(console.error);
}, [])
return (
<>
...
</>
)
}
export default App;
Все остальное работает, только авторизации нет. Кто-нибудь может мне помочь, пожалуйста!
Заранее спасибо.
Вне эффекта использования он будет выполняться при каждом повторном рендеринге, верно? А я только что попробовал, тоже два раза рендерится и выдает ошибку
год, если на уровне компонента приложения будет выполняться повторная обработка, это не будет для вас вариантом, в этом случае вы, вероятно, захотите попробовать «флаг выполнения аутентификации». Как и ответ, приведенный ниже, но вам нужно вручную установить флаг перед началом запроса, а не просто проверять завершение аутентификации, как предложил другой пользователь.
Создайте свое приложение локально. Это почти наверняка больше не повторится, но React делает это намеренно. Они пытаются заставить вас ловить подобные ошибки сейчас, а не полагаться на время, которое обычно работает. После удаления строгого режима в режиме разработки он будет запускаться только один раз, но для этого не следует удалять строгий режим. Попробуйте создать ссылку на загрузку и установить для нее значение true при отправке первоначального запроса, а затем значение false, когда обещание будет разрешено, и проверьте эту ссылку перед отправкой запроса.
Я пытаюсь это сделать с помощью этого кода: асинхронная функция setupDiscordSdk() { console.warn('Пытаюсь войти в систему', isAuthing); если (isAuthing) возврат; setIsAuthing (истина); ... но он дважды регистрирует «попытку входа в систему - false».. (isAuthing - это useState(false))
Обновлено: добавил useRef (не знал, что он делает, лол), и, похоже, он работает
Функция setupDiscordSdk может запускаться дважды из-за находящегося в разработке React StrictMode, который намеренно дважды вызывает определенные методы жизненного цикла (включая useEffect).
можете ли вы просто добавить условие if в свой useEffect?
useEffect(() => {
if (!auth) setupDiscordSdk()
}, [auth]);
Это тоже не работает, та же проблема: происходит двойной рендеринг и ошибка.
проблема в том, что запрос отправляется дважды, прежде чем завершиться. добавьте в свой ответ собственный флаг, который переключается до начала запроса и после его завершения, и вы будете близки к правильному ответу;)
Исправил с помощью комментариев и самостоятельно. Вот мой обновленный код:
function App() {
const [auth, setAuth] = useState<authType>(null);
const [isAuthing, setIsAuthing] = useState(false);
const [showLeaderboard, setShowLeaderboard] = useState(false);
const hasInitialized = useRef(false);
async function setupDiscordSdk() {
console.warn('Trying to login');
if (isAuthing) return;
setIsAuthing(true);
const CLIENT_ID = "1170963763340517466";
const discordSdk = new DiscordSDK(CLIENT_ID, { disableConsoleLogOverride: true });
await discordSdk.ready();
console.warn('DISCORD SDK READY!')
// ...
setAuth(authing);
console.warn('AUTHED SUCCESSFULLY.');
setIsAuthing(false);
}
useEffect(() => {
if (!hasInitialized.current) {
setupDiscordSdk();
hasInitialized.current = true;
}
}, []);
К вашему сведению, использование ссылок «isMounted», «isInitialized» и т. д. уже некоторое время считается антишаблоном. Вы оптимизируете непроизводственную «проблему».
в режиме разработки реакция выполняет двойной рендеринг, чтобы обнаружить подобные ошибки. начал бы с добавления флага, который проверяет, что аутентификация идентификатора уже выполняется, и учитывает, что вам может не понадобиться метод setupDiscordSdk внутри эффекта использования.