如何等待数据被填充到反应中?
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 ? (<PetDataContext />) : "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>
);
【讨论】:
以上是关于如何等待数据被填充到反应中?的主要内容,如果未能解决你的问题,请参考以下文章