如何等待数据在反应中被填充?
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
状态保持有效值时的实际内容。在那之前,您可以展示一些基本的加载器,就像您在网站上看到的那种,也许是微调器或其他东西。
我遇到了一个奇怪的问题,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
状态保持有效值时的实际内容。在那之前,您可以展示一些基本的加载器,就像您在网站上看到的那种,也许是微调器或其他东西。