【问题标题】:how can i render a component with an API call with props react js我如何使用 props react js 使用 API 调用渲染组件
【发布时间】:2020-11-01 23:23:17
【问题描述】:

我正在尝试使用我传递的 prop 渲染一个调用 api 的组件,但我有这个错误:错误:对象作为 React 子级无效(找到:[object Promise])。如果您打算渲染一组子项,请改用数组。

还有一些说它无法读取 null 的属性映射,这是我的代码

import React, { useEffect } from "react";

const GetLeagues = async (country) => {
    const url = `https://www.thesportsdb.com/api/v1/json/1/search_all_leagues.php?c=${country}&s=Soccer`;
    const res = await fetch(url);
    const { countrys } = await res.json();

    return (
        <div>
            <ul>
                {countrys.map((country, i) => {
                    return <li key={i}>{country.strLeague}</li>;
                })}
            </ul>
        </div>
    );
};

const Leagues = () => {
    useEffect(() => {
        GetLeagues();
    }, []);

    return (
        <div>
            <GetLeagues country={"Spain"} />
        </div>
    );
};

export default Leagues;

【问题讨论】:

  • 一个函数组件永远不能通过async function,因为在渲染时渲染引擎想知道在调用的那一刻要渲染什么。 async function 总是返回一个 Promise 并且 Promise 不能被渲染,因为在 Promise 解决之前该值不可用。

标签: javascript reactjs jsx


【解决方案1】:

你不应该在组件体中产生副作用,你应该使用useEffect来产生副作用,因此你不应该让你的组件async而是你可以将你的函数定义为异步,使用它们在useEffect 中,然后设置您的状态。

function Leagues({ country }) {
  const [countryData, setCountryData] = React.useState([]);

  React.useEffect(() => {
    async function getCountries() {
      const url = `https://www.thesportsdb.com/api/v1/json/1/search_all_leagues.php?c=${country}&s=Soccer`;
      const res = await fetch(url);
      const { countrys } = await res.json();
      setCountryData(countrys);
    }

    getCountries();
  }, [country]);

  return (
    <div>
      <ul>
        {countryData.map((country, i) => {
          return <li key={i}>{country.strLeague}</li>;
        })}
      </ul>
    </div>
  );
}

ReactDOM.render(
  <Leagues country="Spain"  />,
  document.getelementById("root")
);

由于 sn-p 不支持 async 函数,这里有一个带有 .then 承诺链的工作版本。

function Leagues({ country }) {
  const [countryData, setCountryData] = React.useState([]);

  React.useEffect(() => {
    const url = `https://www.thesportsdb.com/api/v1/json/1/search_all_leagues.php?c=${country}&s=Soccer`;
    fetch(url)
      .then((res) => res.json())
      .then(({ countrys }) => setCountryData(countrys));
  }, [country]);

  return (
    <div>
      <ul>
        {countryData.map((country, i) => {
          return <li key={i}>{country.strLeague}</li>;
        })}
      </ul>
    </div>
  );
}

ReactDOM.render(
  <Leagues country="Spain" />,
  document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root" />

【讨论】:

    【解决方案2】:

    这里是组件,在App中用&lt;Leagues c='Spain'/&gt;调用即可 我称参数为c,因为country 显然不可读,到处都有countrys

    import React, { useEffect, useState } from "react";
    
    
    const Leagues = ({c}) => {
        const [countrys, countrysSet] = useState(false);
    
        useEffect(() => {
            countrysSet(false);
            const url = `https://www.thesportsdb.com/api/v1/json/1/search_all_leagues.php?c=${c}&s=Soccer`;
            fetch(url).then( res => res.json()).then(countrysSet);
        }, [c]);
    
        if( countrys === false ) {
            return <p>loading...</p>;
        }
    
        return (
            <div>
                <ul>
                    {countrys.map((country, i) => {
                        return <li key={i}>{country.strLeague}</li>;
                    })}
                </ul>
            </div>
        );
    };
    
    export default Leagues;
    

    【讨论】:

    • useEffect里面的async/await代码不应该写在另一个async函数里吗?并在 useEffect 回调中调用该函数。
    • 我编辑了,现在没有异步了。是不是更清楚了?
    【解决方案3】:

    我认为您应该将该代码分解为几个部分。此外,您不能在函数体中进行 api 调用,否则每次重新渲染组件时它都会运行。让我用你的例子告诉你:

    import React, { useEffect, useState } from "react";
    
       const GetLeagues = async (country) => {
           // This helper function fetches your leagues
           const url = 'your url'
           const res = await fetch(url);
           const { countries } = await res.json();
       
           return countries;
       };
       
       const Leagues = () => {
           const [leagues, setLeagues] = useState([]);
    
           useEffect(() => {
              async function init() {
              // Declaring an extra function as useEffect
              // cannot be async.
               const countries = await GetLeagues();
                setLeagues(countries);
               }
               init();
           }, []);
       
           return (
               <div>
                    {leagues.map((country, i) => {
                       return <li key={i}>{country.strLeague}</li>;
                   })}
               </div>
           );
       };
    
       export default Leagues;
    
    

    请注意,现在“GetLeagues”只是一个实用功能,而不是 React 组件。这样就可以在不渲染任何内容的情况下重复使用。

    此外,您的“Leagues”组件会处理所有必要的操作来呈现自己。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-10-31
      • 1970-01-01
      • 2016-03-19
      • 1970-01-01
      • 2018-01-11
      • 2016-06-06
      • 2016-07-02
      相关资源
      最近更新 更多