【问题标题】: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

标签: reactjs axios fetch react-context use-context


【解决方案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>
  );
}

【讨论】:

    猜你喜欢
    • 2021-07-07
    • 2017-12-21
    • 2015-11-08
    • 2019-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-30
    • 2016-07-18
    相关资源
    最近更新 更多