useState передавать асинхронно с useEffect

Есть функция которая перебирает url как массив, и мне нужно перенести эти urls в другой fetch запрос. И тут возникла проблема, что хук не отрабатывает с первого раза. url2 это то, что я хочу передать

//Функция работает по клику
let getDataCategory = async (event) => {
let id = event.currentTarget.id;

        await fetch(`http://api.tmweb.ru/category?filter[parent_id][in]=${id}&filter[type]=0`,{
            headers: {
                'Accept': 'application/json',
                'Authorization': token,
            },
        })
  .then(res => res.json())
            .then((result) => {
                    setCategoryUrl(result.data)
                    setCategorySub([...categorySub,...result.data]);
                    let url2 = `http://api.tmweb.ru/object?filter[category_id][in][]=${id}&`
                    result.data.forEach(item => {url2 += 'filter[category_id][in][]=' + item.id + '&'})
                    setCategoryUrl(url2) // Вот это нужно передать
            });

// Cюда передаю, url генерируется правильно, но генерируется не с первого клика
            await fetch(`${categoryUrl}&filter[type]=0`,{
                headers: {
                    'Accept': 'application/json',
                    'Authorization': token,
                },
            })
}

Пробовал useEffect, но он тоже не особо помог. Отрабатывается всё с задержкой.

useEffect(()=>{
        console.log(categoryUrl)
        }, [categoryUrl])

Тут полный код кому интересно

//Это категории по которым кликаю
    useEffect(() => {
        fetch('http://api.tmweb.ru/category?filter[depth]=1&filter[type]=0',{
            headers: {
                'Accept': 'application/json',
                'Authorization': token,
            }
        })
            .then(res => res.json())
            .then((result) => setCategory(result.data),
            )
    }, [])

    useEffect(()=>{
        console.log(categoryUrl)
    }, [categoryUrl])

//Клик по категориям
let getDataCategory = async (event) => {
        let id = event.currentTarget.id;

//Проверка чекбокса

        if (event.target.checked){
        await fetch(`http://api.tmweb.ru/category?filter[parent_id][in]=${id}&filter[type]=0`,{
            headers: {
                'Accept': 'application/json',
                'Authorization': token,
            },
        })
            .then(res => res.json())
            .then((result) => {
//Тут подкатегории и выбор url
                    setCategoryUrl(result.data)
                    setCategorySub([...categorySub,...result.data]);
                    let url2 = `http://api.tmweb.ru/object?filter[category_id][in][]=${id}&`
                    result.data.forEach(item => {url2 += 'filter[category_id][in][]=' + item.id + '&'})
                    setCategoryUrl(url2)
            });

//Тут должны выводиться подкатегории
            await fetch(`${categoryUrl}&filter[type]=0`,{
                headers: {
                    'Accept': 'application/json',
                    'Authorization': token,
                },
            })
                .then(res => res.json())
                .then((result) => {
                    console.log(result)
                    setCategoryProd([...categoryProd,...result.data])
                })
//Удаление элементов
        }else {
            // Удаляете элемент из состояния
            setCategorySub((prevData) => { //prevData текущее состояние
                return prevData.filter((item) => item.parent_id !== +id);
            });
            setCategoryProd((prevData) =>{
                return prevData.filter((item) => item.category_id !== +id);
            })
        }
    }

Ответы (2 шт):

Автор решения: SwaD

Передаем асинхронно данные для обработки в функциональном компоненте React

Вариант #1 - Используем цепочку промисов then() для передачи данных

let getDataCategory = async (event) => {
  let id = event.currentTarget.id;

//Проверка чекбокса

  if (event.target.checked) {
    await fetch(`http://api.tmweb.ru/category?filter[parent_id][in]=${id}&filter[type]=0`, {
      headers: {
        'Accept': 'application/json',
        'Authorization': token,
      },
    })
      .then(res => res.json())
      .then((result) => {
        //Тут подкатегории и выбор url
        setCategorySub([...categorySub, ...result.data]);
        let url2 = `http://api.tmweb.ru/object?filter[category_id][in][]=${id}&`
        result.data.forEach(item => {
          url2 += 'filter[category_id][in][]=' + item.id + '&'
        })
        setCategoryUrl(url2)
        return url2; // Передаем url дальше, не дожидаясь изменения состояния компонента
      })
      .then(url => 
        // выполняем необходимый запрос и отправляем данные для сохранения в состоянии компонента
        fetch(`${url}&filter[type]=0`, {
          headers: {
            'Accept': 'application/json',
            'Authorization': token,
          },
        })
          .then(res => res.json())
          .then((result) => setCategoryProd([...categoryProd, ...result.data]))
      );
//Удаление элементов
  } else {
    // Удаляете элемент из состояния
    setCategorySub((prevData) => { //prevData текущее состояние
      return prevData.filter((item) => item.parent_id !== +id);
    });
    setCategoryProd((prevData) => {
      return prevData.filter((item) => item.category_id !== +id);
    })
  }
}

Вариант №2 - Используем хук useEffect функционального компонента React для того что бы при изменении состояния переменной categoryUrl произвести новый запрос для выборки данных с новыми параметрами.

useEffect - отслеживает изменение переменных функционально компонента и выполняет код, указанный в callBack функции каждый раз, когда переменная из указанных в зависимостях изменилась.

Общий вид хука useEffect(() => { code }, [dep1, dep2, depN]);

useEffect(() => { // делаем асинхронной функцию
  // Выполняем fetch запрос с обновленным значением categoryUrl
  fetch(`${categoryUrl}&filter[type]=0`, {
    headers: {
      'Accept': 'application/json',
      'Authorization': token,
    },
  })
    .then(res => res.json())
    .then((result) => setCategoryProd([...categoryProd, ...result.data]))
}, [categoryUrl]) // Будет срабатывать при каждом изменении categoryUrl 

//Клик по категориям
let getDataCategory = async (event) => {
  let id = event.currentTarget.id;

//Проверка чекбокса

  if (event.target.checked) {
    await fetch(`http://api.tmweb.ru/category?filter[parent_id][in]=${id}&filter[type]=0`, {
      headers: {
        'Accept': 'application/json',
        'Authorization': token,
      },
    })
      .then(res => res.json())
      .then((result) => {
        //Тут подкатегории и выбор url
        setCategorySub([...categorySub, ...result.data]);
        let url2 = `http://api.tmweb.ru/object?filter[category_id][in][]=${id}&`
        result.data.forEach(item => {
          url2 += 'filter[category_id][in][]=' + item.id + '&'
        })
        setCategoryUrl(url2)
        return url2;
      });

  //Удаление элементов
  } else {
    // Удаляете элемент из состояния
    setCategorySub((prevData) => { //prevData текущее состояние
      return prevData.filter((item) => item.parent_id !== +id);
    });
    setCategoryProd((prevData) => {
      return prevData.filter((item) => item.category_id !== +id);
    })
  }
}
→ Ссылка
Автор решения: Александр

Нашёл ещё один вариант через переменную.


let getDataCategory = async (event) => {
        let id = event.currentTarget.id;
        let newUrl = ''; // Создаем новую переменную

        if (event.target.checked){
        await fetch(`http://api.tmweb.ru/category?filter[parent_id][in]=${id}&filter[type]=0`,{
            headers: {
                'Accept': 'application/json',
                'Authorization': token,
            },
        })
            .then(res => res.json())
            .then((result) => {
                    setCategorySub([...categorySub,...result.data]);
                    let url2 = `http://api.tmweb.ru/object?filter[category_id][in][]=${id}&`
                    result.data.forEach(item => {url2 += 'filter[category_id][in][]=' + item.id + '&'})
                    newUrl = url2; //присваиваем новое значение
            });


            await fetch(`${newUrl}&filter[type]=0`,{
                headers: {
                    'Accept': 'application/json',
                    'Authorization': token,
                },
            })
→ Ссылка