【问题标题】:Struggling With JS Promises in React在 React 中与 JS Promises 作斗争
【发布时间】:2021-01-15 20:26:27
【问题描述】:

我正在为 JavaScript 中的 Promise 概念而苦苦挣扎。我正在编写一个 React 应用程序,它使 GET 调用 Java 中的单独 API 服务,我想将其状态存储在 useState() 挂钩中。所以这是我的fetch 代码:

const ratingsUrl = "%URL%";
const base64 = require("base-64");
const login = "login";
const password = "password";

function fetchRatings() {
  return fetch(ratingsUrl, {
    method: "GET",
    headers: new Headers({
      Authorization: "Basic " + base64.encode(login + ":" + password),
    }),
  })
    .then((response) => response.json())
    .catch(handleError);
}

现在我正在尝试将其状态存储在我的页面组件中的挂钩中:

function DisplayPage(){
  const [ratings, setRatings] = useState(fetchRatings());

.
.
.
}

现在,数据返回,但它位于 Promise 中,因此导致错误:

Promise {<pending>}
__proto__: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: Array(20)

我需要做的是在一个钩子中初始化数据并在Table 中返回它,这样我就可以映射它。但是,每当我尝试做类似的事情时

ratings.map()

我在控制台中收到一个 TypeError 提示 ratings.Map is not a function

我知道fetch 库异步返回数据,但我真正想要的只是将PromiseResult 存储在useState() 钩子中,这样我就可以进一步对其执行操作。

【问题讨论】:

  • fetchRatings 返回一个 Promise ...使用您已经知道的 Promise 方法来获得承诺的价值(即您需要使用 .then

标签: javascript reactjs asynchronous promise fetch-api


【解决方案1】:

由于 fetch 是异步运行的,因此您将无法使用调用 fetchRatings 的即时结果来初始化您的状态。

幸运的是,有几种相当简单的方法可以处理这个问题。您可以使用空值初始化您的状态,然后在 fetchResults 解析后更新它:

function DisplayPage() {
  // initially ratings will be undefined
  const [ratings, setRatings] = useState();

  // update state when fetchResults comes back
  fetchResults().then(response => setRatings(response));

  // ...

为了便于阅读,上面的示例省略了这一点,但您通常会通过useEffect 执行此操作,因此它会在您的组件安装或相关输入(通常是道具,称为效果的依赖项)发生更改时运行:

function DisplayPage() {
  const [ratings, setRatings] = useState();

  useEffect(() => {
    fetchResults().then(response => setRatings(response));
  }, []) // empty dependencies array will cause the effect to run only once, on mount

  // ...

【讨论】:

    【解决方案2】:

    我建议使用 useEffect 挂钩来设置初始状态。(类似于 componentDidMount)

    因此,如果您期望的响应是例如一个数组。

    const [ratings, setRatings] = useState([]);
    

    然后在 useEffect 挂钩中,当您从获取请求中获得响应时更新状态。 这样,如果您在请求完成之前在 DOM 中的某处映射评级,则可以防止错误。

    useEffect(){
        fetch(ratingsUrl, {
            method: "GET",
            headers: new Headers({
                Authorization: "Basic " + base64.encode(login + ":" + password),
            }),
        })
        .then((response) => {
             response.json()
        })
        .then(res => setRatings(res))
        .catch(handleError);
    

    【讨论】:

      【解决方案3】:

      这个怎么样,

      const [ratings, setRatings] =  useState();
      useEffect(()=>{
               fetch(ratingsUrl, {
      method: "GET",
      headers: new Headers({
        Authorization: "Basic " + base64.encode(login + ":" + password),
      })}).then((response) => {let res = response.json();
          setRatings(res)
            })
      .catch(handleError);
       },[])
      

      【讨论】:

        【解决方案4】:

        async 方法返回承诺。如果你直接在你的setRatings状态变量中设置一个promise的结果,你会得到一个promise。

        通常会这样重写:

        function DisplayPage(){
          const [ratings, setRatings] = useState(null);
        
          useEffect(() => {
        
            fetchRatings
              .then(result => setRatings(result))
              .catch(err => console.error(err));
        
          }, []);
         
          if (ratings === null) return <div>loading...</div>;
          
          /* .. do your thing .. */
        
        }
        

        【讨论】:

        • 谢谢,它解决了一些最初的错误——但是,当我想返回一个 Table 并映射到之前实例化的 ratings 对象时,我仍然得到一个 ratings.Map不是函数...
        • 1.当评级仍然为null 时返回加载程序是必要的,就像我在我的示例中所做的那样。 2. 如果 ratings 是一个数组,你可能在寻找 .map 函数,而不是 .Map 函数。
        猜你喜欢
        • 2019-08-10
        • 2021-03-08
        • 2015-12-07
        • 2013-08-15
        • 1970-01-01
        • 1970-01-01
        • 2016-03-01
        • 1970-01-01
        • 2022-01-08
        相关资源
        最近更新 更多