Задать вопрос
@kelwin27

Как правильно обработать данные get запрос?

При получение данных с внешнего АПИ для дальнейшей валидации и размещения на странице возникает ошибка при попытке положить данные в useState переменную. Получается, что React пытается сформировать страницу до получения данных с АПИ. Подскажите пожалуйста, как это побороть.
Код запроса на АПИ:
import React from "react";
import axios from "axios";

export default function RouteQuestions() {
    const [questions, setQuestions] = React.useState([])
    
        React.useEffect(() => {
        axios.get("https://opentdb.com/api.php?amount=5&category=17&difficulty=easy&type=multiple")
        .then(response => setQuestions(response.data.results))

    }, [])

    return questions
}

место где осуществляется вызов и происходит ошибка(На данном этапе React пытается отрисовать страницу при помощи пустого массива.):
export default function Question() {
    
    const [questions, setQuestions] = React.useState(FilterQuestions()) // здесь происходит 
//постановка данных после их структурирования, однако вместо данных подставляется пустой массив

    return (
        <div className="allQ">
            <img src={blob} className="blob1" />
            <div className="textQ">
                {questions.map(item => <div key={item.id}>{QuestionItem(item)}</div>)}
            </div>
            <div>
                <button>Check answers</button>
            </div>
            <img src={blob_blue} className="blob2" />
        </div>
    )
}

Однако если я помещаю данные в переменную без отслеживания состояния questions = FilterQuestions() страница отрисовывается. Но дело в том, что в объекте, который передается находятся элементы состояния, которые я планировал менять в процессе работы в chiild элементах. Подскажите, будьте добры, как можно решить подобную ситуацию.
  • Вопрос задан
  • 493 просмотра
Подписаться 1 Простой 2 комментария
Решения вопроса 1
@kelwin27 Автор вопроса
Всем большое спасибо за ответы!
Ошибка была не там, где я думал. Уважаемый Kentavr16 правильно заметил на лишний элемент в декомпозиции, а именно упорядочивание результатов запроса. Я избавился от этого компонента. Get запрос на АПИ переписал как метод класса, а сам запрос обернул в async/await:
export default class RouteQuestions {
    static async getAll (){

        const response = await axios.get("https://opentdb.com/api.php?amount=5&category=17&difficulty=easy&type=multiple")

        const preQuestions = response.data.results
        const newQuestions = []
    
        for (let i = 0; i < preQuestions.length; i++) {
    
        const answ = [...preQuestions[i].incorrect_answers, preQuestions[i].correct_answer]
        const answers = []
    
        for (let i = 0; i < answ.length; i++){
            
            answers.push({
                value: answ[i],
                id: nanoid(),
                isHold: false
            })
        }
            newQuestions.push({
                answer: preQuestions[i].correct_answer,
                id: nanoid(),
                text: preQuestions[i].question,
                answers: answers
            })}
            return newQuestions
        }
    }

Обращение к данному методу обернул в useEffect и добился необходимой функциональности:
const [questions, setQuestions] = React.useState([])

    React.useEffect( () => { 
        async function fetchQuestions() {
            const questions = await RouteQuestions.getAll()
            setQuestions(questions)
        }
        fetchQuestions()
    }, [])

Буду очень благодарен, если кто-нибудь объяснит, почему код начал работать, заранее благодарен за ваше потраченное время.
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
@n1ksON
мидл
Можете использовать useLayoutEffect, либо выполнять проверку на длину и показывать иное, типа:
{array.length > 0 ? <div>content</div> : <div>empty</div>}
Ответ написан
Kentavr16
@Kentavr16
long cold winter
Я не эксперт, но насколько я понимаю ваш код это плохая практика. Вы создаете компонент(!) который существует только для того чтобы сделать запрос и вернуть полученные данные. Подобная работа для обычных функций, а не компонентов. Просто совершайте запрос к сети в том компоненте, который будет использовать ответ. Если ответ сервера будут использовать несколько компонентов - делайте запрос в их родителе и распространяйте все через пропсы. Чтобы реакт не отрисовывал пока еще пустой стейт можно использовать условный рендеринг - если стейт null - вернуть какой-то прелоадер, если стейт обновлен данными из сети - отрисовать полноценный компонент.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы