Можете ли вы использовать асинхронную функцию для установки начального состояния с помощью useState

Мой компонент зависит от локального состояния (useState), но начальное значение должно исходить из ответа http.

Могу ли я передать асинхронную функцию для установки начального состояния? Как я могу установить начальное состояние из ответа?

это мой код

  const fcads = () => {
    let good;
    Axios.get(`/admin/getallads`).then((res) => {
      good = res.data.map((item) => item._id);
    });
    return good;
  };

  const [allads, setAllads] = useState(() => fcads());

Но когда я пытаюсь console.info(allads) я получил результат undefined.

Где ты делал console.info(allads)?

MacOS 21.12.2020 10:36

Я делаю кнопку и делаю onclick для console.info(allads) @MacOS

test tet 21.12.2020 10:42

Используйте хук useEffect и вызовите сервер внутри него.

adiga 21.12.2020 10:42

Кроме того, вы не можете использовать good = res.data внутри обратного вызова и return good снаружи. return вызывается перед запуском обратного вызова. Как вернуть ответ при асинхронном вызове?

adiga 21.12.2020 10:46

Я пытался, как вы сказали, но все еще не определился @adiga

test tet 21.12.2020 10:54
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
Раскрытие чувствительных данных
Раскрытие чувствительных данных
Все внешние компоненты, рассмотренные здесь до сих пор, взаимодействуют с клиентской стороной. Однако, если они подвергаются атаке, они не...
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Руководство ChatGPT по продаже мини JS-файлов
Руководство ChatGPT по продаже мини JS-файлов
JS-файл - это файл, содержащий код JavaScript. JavaScript - это язык программирования, который в основном используется для добавления интерактивности...
6
5
6 066
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете использовать пользовательский хук, чтобы включить функцию обратного вызова для useState с пакетом use-state-with-callback npm.

npm install use-state-with-callback

Для вашего случая:

import React from "react";
import Axios from "axios";
import useStateWithCallback from "use-state-with-callback";

export default function App() {
  const [allads, setAllads] = useStateWithCallback([], (allads) => {
    let good;
    Axios.get("https://fakestoreapi.com/products").then((res) => {
      good = res.data.map((item) => item.id);
      console.info(good);
      setAllads(good);
    });
  });

  return (
    <div className = "App">
      <h1> {allads} </h1>
    </div>
  );
}


Демонстрация и код: https://codesandbox.io/s/distracted-torvalds-s5c8c?file=/src/App.js

Я действительно не знаю, как это использовать, вы можете привести пример?

test tet 21.12.2020 10:44

@testtet - обновил мой ответ примером.

Shankar Ganesh Jayaraman 21.12.2020 10:59

Извини, братан, ты уверен, что твой код не неверен? Я пытался, но все еще не определено

test tet 21.12.2020 11:20

Да, это сработает. Я не уверен, каким будет ваш ответ API. Поэтому я использовал поддельный API, чтобы помочь вам. проверить - codeandbox.io/s/distracted-torvalds-s5c8c?file=/src/…

Shankar Ganesh Jayaraman 21.12.2020 11:51

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

Код, показанный в вашем примере, является асинхронным — он использует обещание, которое устанавливает значение только после завершения запроса.

Вы пытаетесь загрузить данные, когда компонент визуализируется в первый раз — это очень распространенный вариант использования, и существует множество библиотек, которые его обрабатывают, например эти популярные варианты: https://www.npmjs.com/package /react-async-hook и https://www.npmjs.com/package/@react-hook/async. Они не только установят данные для отображения, но и предоставят вам флаг для использования и отобразят загрузчик или отобразят ошибку, если это произошло.

Это в основном то, как вы устанавливаете начальное состояние, когда вам нужно установить его асинхронно.

const [allads, setAllads] = useState([]);
const [loading, setLoading] = useState(false);

React.useEffect(() => {
  // Show a loading animation/message while loading
  setLoading(true);

  // Invoke async request
  Axios.get(`/admin/getallads`).then((res) => {
    const ads = res.data.map((item) => item._id);
    // Set some items after a successful response
    setAllAds(ads):
  })
  .catch(e => alert(`Getting data failed: ${e.message}`))
  .finally(() => setLoading(false))
// No variable dependencies means this would run only once after the first render
}, []);

Думайте о начальном значении useState как о чем-то необработанном, что вы можете установить немедленно. Вы знаете, что вы будете отображать обработку списка (массива) элементов, тогда начальное значение должно быть пустым массивом. useState принимайте функцию только для покрытия немного более дорогих случаев, которые в противном случае оценивались бы при каждом проходе рендеринга. Как чтение из локального/сеансового хранилища

const [allads, setAllads] = useState(() => {
  const asText = localStorage.getItem('myStoredList');
  const ads = asText ? JSON.parse(asText) : [];
  return ads;
});

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