Ошибка асинхронной функции в триггерах React: объекты недопустимы как дочерние элементы React (найдено: [обещание объекта])

#javascript #reactjs #async-await

#javascript #reactjs #асинхронное ожидание

Вопрос:

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

Кроме того, если в цикле сокращения есть ошибка, мне нужно остановить функцию и вернуть значение null. Формат try / catch кажется подходящим. Однако React утверждает, что:

Объекты недопустимы как дочерние элементы React (найдено: [обещание объекта]). Если вы хотели отобразить коллекцию дочерних элементов, вместо этого используйте массив.

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

 async function test(name){
    try{
      if(!name) {
        throw new Error
      }
      const formattedName = name.toUppercase()
      return formattedName
    }
    catch{
      return "error"
    }
}

export default function App() {
  return (
    <>
     {test("joe")}
    </>
  );
}  

Как это исправить?

Комментарии:

1. Если вы await не используете асинхронную функцию, она вернет объект promise, а не значение you return .

2. Даже при использовании const formattedName = await name.toUpperCase() ошибка остается.

3. Да, await не останавливает функцию, чтобы продолжать возвращать обещание

4. » По этой причине мне нужно, чтобы он был асинхронным, чтобы не задерживать рендеринг компонентов». — нет, это не так, как это работает. Ваш алгоритм не является асинхронным, и он не должен быть помечен как async . И в настоящее время ваш компонент не может обрабатывать рендеринг без результата алгоритма — это то, что вам нужно будет исправить.

Ответ №1:

Я не знаю, каков ваш вариант использования, но, вероятно, вы просто хотите иметь состояние в React, которое содержит имя или любое значение, которое вы хотите, а затем отображать это значение, если оно доступно, что-то вроде:

 const [name, setName] = useState("")

async function test(name){
    try{
      if(!name) {
        throw new Error
      }
      const formattedName = name.toUppercase()
      setName(formattedName)
    }
    catch{
      return "error"
    }
}

export default function App() {
  return (
    <>
     {name}
    </>
  );
}
  

РЕДАКТИРОВАТЬ: Предположим, что у вас есть эта js функция в utils папке или что-то еще, что выполняет весь упомянутый вами синтаксический анализ. Вы можете рассматривать это как асинхронный вызов API, то, что вам нужно, находится в вашем компоненте React (предположим, при первом рендеринге), следующее:

 const [data, setData] = useState(...)

useEffect(async () => {
  const data = await callToYourParsingFunctionThatIsAsync();
  setData(data);
}, [])
  

И затем вы отображаете все, что вам нужно, из этой data переменной

Комментарии:

1. Нет, это функция трансляции за пределами области действия React. Он проверяет огромный файл json и возвращает правильный динамический перевод. Поэтому я не могу использовать какое-либо состояние.

2. Так в чем проблема? Вы можете продолжать устанавливать состояние. Редактирую мой ответ прямо сейчас

3. Проблема в том, что если у меня будет 600 вызовов этой функции в моем приложении, мне понадобится так много состояний. Это не чистая архитектура.

4. Я не совсем понимаю ваш вариант использования, но у вас может быть HOC (компонент высокого порядка) или поставщик контекста, который будет сохранять только одно состояние, и вы можете поделиться функцией трансляции с тем, кому это нужно. Но ответ таков. Пожалуйста, отметьте как правильный ответ, если он подходит

Ответ №2:

 import React, { useState } from "react";

export default function App() {
  const [name, setName] = useState("");

  async function test(innerName) {
    if (innerName === name) {
      return;
    }
    try {
      if (!innerName) {
        throw new Error();
      }
      const formattedName = innerName;
      setName(formattedName);
    } catch {
      return "error";
    }
  }

  test("Joe");

  return <>{"Testing : "   name}</>;
}
  

Вам необходимо использовать состояние для обновления рендеринга при будущем событии во времени. Пример кода выглядит так, как указано выше.

Комментарии:

1. Но если у меня будет 600 вызовов этой функции в моем приложении, мне понадобится так много состояний… Я думаю, мне нужно найти другой способ обработки ошибок внутри reduce.

2. @DoneDeal0 ЧТО делает эта функция? Как вы думаете, почему это дорого, но все равно вызывает его 600 раз?

3. это функция перевода, которая проверяет огромный файл json и возвращает правильную динамическую строку на основе предоставленного ключа и параметров. Я не могу добавлять состояние каждый раз, когда я его использую, это безумие.