Перед рендерингом представления убедитесь, что Promise решен

Какой конкретный синтаксис необходимо изменить в приведенном ниже коде, чтобы значение, возвращаемое функцией currentSession(), правильно задавало HTML-код, отображаемый пользователю в веб-браузере?

В частности, что нужно изменить, чтобы строка console.info("other groups is: ", groups); возвращала действительный массив групп и чтобы логика в строке {isGroupOne ? <p>Welcome back!</p> : <p>Please log in.</p>} могла выполняться с isGroupOne, возвращенным как True?

СЛУЧАЙ ИСПОЛЬЗОВАНИЯ:

Компоненту React необходимо отображать разный контент для пользователей, находящихся в разных группах пользователей. Группы для данного пользователя действительно возвращаются из серверной службы.

ПРОБЛЕМА:

Проблема в том, что компонент React распечатывает группы пользователя как ожидающее обещание, а не как действительный массив имен групп, который можно преобразовать в логическое значение, чтобы указать, находится ли пользователь в определенной группе.

В результате в веб-браузере выводится неправильный контент в приведенном ниже примере неработающего кода. В настоящее время Please log in. печатается в браузере, хотя из журналов ниже видно, что обещание в конечном итоге разрешается дать isGroupOne значение true.

МИНИМАЛЬНЫЙ КОД ДЛЯ ВОСПРОИЗВЕДЕНИЯ ПРОБЛЕМЫ:

Вот минимальный код, необходимый для воспроизведения проблемы:

import { fetchAuthSession } from 'aws-amplify/auth';

function Index() {
  let isGroupOne = false;

  async function currentSession() {
    try {
      const { accessToken, idToken } = (await fetchAuthSession()).tokens ?? {};
      const groups = accessToken["payload"]["cognito:groups"]
      console.info("these groups: ", groups);
      return groups;
    } catch (err) {
      console.info(err);
    }
  }

  const groups = currentSession().then(groups => {
    console.info("those groups is: ", groups);
    //iterate groups array to see if "GroupOne" is in the array
    groups.forEach(group => {
      if (group === "GroupOne") {
        console.info("User is in GroupOne group");
        isGroupOne = true;
        console.info("isGroupOne: ", isGroupOne);
      }
    });

  });
  console.info("other groups is: ", groups);

  return (
    <div>
        {isGroupOne ? <p>Welcome back!</p> : <p>Please log in.</p>}
    </div>

  );
}

export default Index;

ЖУРНАЛЫ, ИЛЛЮСТРИРУЮЩИЕ ПРОБЛЕМУ:

Следующее сообщение выводится на консоль, когда страница, определенная указанным выше минимальным кодом, отображается в веб-браузере:

other groups is:  Promise {<pending>}
index.js:29 other groups is:  Promise {<pending>}
index.js:10 these groups:  ['GroupOne']
index.js:18 those groups is:  ['GroupOne']
index.js:22 User is in GroupOne group
index.js:24 isGroupOne:  true
index.js:10 these groups:  ['GroupOne']
index.js:18 those groups is:  ['GroupOne']
index.js:22 User is in GroupOne group
index.js:24 isGroupOne:  true

я не разработчик реагирования, поэтому извините, если это невозможно... создайте function Index() функцию async, тогда вы сможете дождаться обещания groups

Jaromanda X 30.07.2024 05:20

@JaromandaX Создание function Index() функции async приводит к другим ошибкам. Я пропустил эти другие ошибки, чтобы упростить этот ФП.

CodeMed 30.07.2024 05:34

как я уже сказал, я не разработчик реагирования, поэтому не знаю, какие ограничения он накладывает

Jaromanda X 30.07.2024 06:07
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
3
67
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете использовать React Hooks для достижения желаемого, а точнее useState и useEffect.

useState помогает вам сохранять состояние, от которого зависят ваши компоненты пользовательского интерфейса — как только состояние будет обновлено, эти компоненты также будут обновлены.

useEffect можно использовать для выполнения кода, который должен обновляться при обновлении какой-либо внешней зависимости (второй параметр функции, в этом примере пустой массив). Используя пустой массив, мы заявляем, что это должно выполняться только один раз (поскольку нет никаких зависимостей, которые могли бы привести к повторному запуску).

import { useEffect, useState } from "react";

// Emulates retrieving the user from Cognito
async function mockedFetchAuthSession(): Promise<{ groups: string[] }> {
  // adjust, save, and reload the page to see diff results
  const groups = ["GroupOne"]; // <-- replace with another group do see diff results
  return new Promise((resolve) => {
    setTimeout(() => resolve({ groups }), 2_000);
  });
}

function groupOne(group: string): boolean {
  return group === "GroupOne";
}

export default function TheIndex() {
  const [isGroupOne, setIsGroupOne] = useState<boolean | null>(null);

  async function currentSession() {
    try {
      const { groups } = await mockedFetchAuthSession();
      console.info("these groups: ", groups);
      setIsGroupOne(groups.some(groupOne));
    } catch (err) {
      console.info(err);
    }
  }

  useEffect(() => {
    currentSession();
  }, []);

  return (
    <div>
      {isGroupOne === null ? (
        <p>Loading...</p>
      ) : isGroupOne ? (
        <p>Welcome back!</p>
      ) : (
        <p>Please log in.</p>
      )}
    </div>
  );
}

Запускающий код: https://codesandbox.io/s/xenodochial-fermi-4mth3h?file=/src/TheIndex.tsx

Спасибо и +1, что нашли время ответить на этот вопрос. Я выбрал вариант, который требует меньше кода, чем ваш. Но спасибо за ваше время. Добро пожаловать в переполнение стека.

CodeMed 30.07.2024 23:28

Без проблем. Обратите внимание: для выбранного вами ответа требуется дополнительная библиотека, и этот ответ был намеренно многословен, чтобы лучше связать его с предоставленным вами кодом. Это может быть намного короче, если это то, что вы ищете.

Raf 31.07.2024 05:29
Ответ принят как подходящий

Это классическая проблема фронтенда: рендеринг данных, которые асинхронно извлекаются из бэкенда.

Здесь нет никакой магии, единственное решение — условно отрисовать загрузочный пользовательский интерфейс во время ожидания данных Backend, а затем, как только они будут получены, вы сможете действовать, как изначально планировалось. Некоторые фреймворки или библиотеки Frontend могут предоставлять помощники для автоматического управления этим поведением, но они всегда реализуют одну и ту же схему «под капотом».

Например, в вашем случае, используя крючок useAsync из реакции-использования:

npm install react-use
import React, { useMemo } from "react";
import { useAsync } from "react-use";

function Index() {
  const groupsAsync = useAsync(currentSession, []); // Fill the dependency array if session should be refreshed on some criteria

  const isGroupOne = useMemo(() =>
    !groupsAsync.loading && 
    groupsAsync.value?.some(
      (group) => group === "GroupOne"
    ), [groupsAsync.loading, groupsAsync.value]);

  return (
    <div>
      {groupsAsync.loading
        ? "Loading..." // Any UI you want as loader, e.g. skeleton, or nothing at all...
        : isGroupOne
        ? <p>Welcome back!</p>
        : <p>Please log in.</p>}
    </div>
  );
}

Спасибо и +1 за то, что вы не только нашли время ответить на мой вопрос, но и за то, что выслушали и уточнили, когда я задал дополнительный вопрос.

CodeMed 30.07.2024 23:29

Другие вопросы по теме