如何等待数据被填充到反应中?

Posted

技术标签:

【中文标题】如何等待数据被填充到反应中?【英文标题】:How to wait for data to be populated in react? 【发布时间】:2021-04-10 15:51:28 【问题描述】:

我遇到了一个奇怪的问题,即 petData 最初以未定义的形式记录到控制台,稍后会填充数据数组。我认为这与获取数据然后通过上下文发送数据所花费的时间有关。问题是应用程序崩溃并出现错误“TypeError:无法访问属性“name”,petData[0] 未定义”我尝试使用 setTimeout 但这没有帮助。有什么解决办法吗?

function SearchPage() 
  const  petData  = useContext(PetDataContext);
  console.log(petData[0].name);

  const [filter, setFilter] = useState("");

  const filteredData = useMemo(() => 
    if (filter == "") return petData;
    return petData.filter(
      (item) =>
        item.name.toLowerCase().includes(filter) ||
        item.breed.toLowerCase().includes(filter)
    );
  , [petData, filter]);

  return (
    <>
      <SearchBar onSearch=(searchTerm) => setFilter(searchTerm) />
      <div className="d-flex flex-wrap sp-body">
        <DogCardsDisplayed petData=filteredData />
      </div>
    </>
  );


export default SearchPage;

App.js

function App() 
  const [petData, setPetData] = useState([]);
  useEffect(() => 
    axios
      .get(`$BACK_PORT/data`)
      .then(function (response) 
        setPetData(response.data);
      )
      .catch(function (error) 
        console.log(error);
        Swal.fire("Oops...", error.response.data, "error");
      );
  , []);
  console.log(petData);
  
  return (
    <div className="App">
      <PetDataContext.Provider value= petData >
        <BrowserRouter>
          <NavBar />
          <Switch>
            <Route path="/" component=MainSignedOut exact />
            <Route path="/mainsignedin" component=MainSignedIn />
            <Route path="/searchpage" component=SearchPage />
            <Route path="/mypets" component=MyPets />
            <Route path="/admin" component=Admin />
            <Route exact path="/pets/:id" component=PetPage />
            <Route component=err404 />
          </Switch>
        </BrowserRouter>
      </PetDataContext.Provider>
    </div>
  );

上下文.js

import  createContext  from "react";
const PetDataContext = createContext([]);
export default PetDataContext;

【问题讨论】:

您有多大把握需要上下文 API 来完成您想要完成的任务? 您正试图在petData 包含任何数据之前访问和记录petData[0].name。您希望编写您的组件以不尝试访问不存在的数据,并可能重写它以处理这种情况并呈现某种回退 UI,直到它有数据要呈现。 那么最好不要使用上下文吗? 除非必要,否则 React 文档不鼓励使用它,因为它增加了复杂性和一些性能考虑。见"Before You Use Context" from the React docs。 【参考方案1】:

试试这个:

function App() 
  const [petData, setPetData] = useState([]);
  useEffect(() => 
    axios
      .get(`$BACK_PORT/data`)
      .then(function (response) 
        setPetData(response.data);
      )
      .catch(function (error) 
        console.log(error);
        Swal.fire("Oops...", error.response.data, "error");
      );
  , []);
  console.log(petData);
  return petData ? (
    <div className="App">
      <PetDataContext.Provider value= petData >
        <BrowserRouter>
          <NavBar />
          <Switch>
            <Route path="/" component=MainSignedOut exact />
            <Route path="/mainsignedin" component=MainSignedIn />
            <Route path="/searchpage" component=SearchPage />
            <Route path="/mypets" component=MyPets />
            <Route path="/admin" component=Admin />
            <Route exact path="/pets/:id" component=PetPage />
            <Route component=err404 />
          </Switch>
        </BrowserRouter>
      </PetDataContext.Provider>
    </div>
  ) : (
    "Loading pets..."
  );

工作原理

这里的想法是,由于网络调用是同步的(它们同时运行,您无法判断它们何时执行),您只需观察petData 将被更新的状态并在petData 时显示实际内容state 持有一个有效值。在此之前,您可以展示一些基本的加载器,例如您在网站上看到的那种,可能是微调器或其他东西。

【讨论】:

如果您将初始状态更改为 null 而不是 [ ],则此方法有效。谢谢! 很好,如果您必须将状态初始化为空数组,您也可以使用return petData.length ? (&lt;PetDataContext /&gt;) : "Loading"【参考方案2】:

试试这个解决方案。修改您的 App.js 文件。我认为你遇到了比赛条件,你必须安装react-async-hook

import  useAsync  from 'react-async-hook';

function App() 

  fetchPetData = () => 
      return  axios
      .get(`$BACK_PORT/data`)
      .then(function (response) 
        return response.data
      )
      .catch(function (error) 
        console.log(error);
        Swal.fire("Oops...", error.response.data, "error");
      );
  

  const value = useAsync(fetchPetData);
  
  return (
    <div className="App">
      <PetDataContext.Provider value= value >
        <BrowserRouter>
          <NavBar />
          <Switch>
            <Route path="/" component=MainSignedOut exact />
            <Route path="/mainsignedin" component=MainSignedIn />
            <Route path="/searchpage" component=SearchPage />
            <Route path="/mypets" component=MyPets />
            <Route path="/admin" component=Admin />
            <Route exact path="/pets/:id" component=PetPage />
            <Route component=err404 />
          </Switch>
        </BrowserRouter>
      </PetDataContext.Provider>
    </div>
  );

【讨论】:

以上是关于如何等待数据被填充到反应中?的主要内容,如果未能解决你的问题,请参考以下文章

Discord.JS 如何等待会员反应

如何让异步/等待等待我的嵌套数组填充

PCL中的MVVMCross异步和等待方法

与条件承诺链反应并在发送调度之前等待它们

如何在 api 调用中使用异步等待获取在反应本机中通过基本身份验证

iOS:在填充表格视图之前等待异步方法