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

How to wait for data to be populated in react?

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

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

试试这个:

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 状态保持有效值时的实际内容。在那之前,您可以展示一些基本的加载器,就像您在网站上看到的那种,也许是微调器或其他东西。