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

问题描述

我遇到了一个奇怪的问题,其中 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>
  );
}

Context.js

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

解决方法

试试这个:

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 时的实际内容{1}} 状态保存有效值。在那之前,您可以展示一些基本的加载程序,比如您在网站上看到的那种,可能是微调器或其他东西。

,

试试这个解决方案。修改您的 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");
      });
  }

  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>
  );
}