[英]React hooks and fetch() advice
我有一个组件可以获取一个随机人,将其保存到 state 变量数组中,并在映射到该数组后返回某些元素。 我的目标是使用头像和个人信息呈现“社交卡”,我想为此使用材质 UI CARD 组件。 另外,我想在这里获得有关我的逻辑的任何反馈,这是否是实现我所取得的成就的好方法。 setTimeout() 只在那里,所以我可以渲染一些加载 animation。 此外,当我尝试返回数组 map 内的完整卡组件时,我无法渲染 {item.something.something}
export default function SocialCardsfunction() {
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(true);
const classes = useStyles();
const nextPerson = () => {
fetch("https://randomuser.me/api")
.then((response) => response.json())
.then((response) => {
setItems(response.results);
});
};
useEffect(() => {
fetch("https://randomuser.me/api")
.then((response) => response.json())
.then((response) => {
setTimeout(() => {
setItems(response.results);
setLoading(false);
}, 1000);
});
}, []);
if (loading) {
return <div>Loading ...</div>;
} else {
return (
<div>
{items.map((item, i) => {
return (
<div>
<h2>{item.name.first}</h2>
<img src={item.picture.large} alt='picture' key={i} />
<button onClick={() => nextPerson()}>click me</button>
</div>
);
})}
</div>
);
}
}
const useStyles = makeStyles({
root: {
minWidth: 275,
},
bullet: {
display: "inline-block",
margin: "0 2px",
transform: "scale(0.8)",
},
title: {
fontSize: 14,
},
pos: {
marginBottom: 12,
},
});
所做的更改
useEffect
。key
”道具。import {
Button,
Card,
CardActions,
makeStyles,
} from "@material-ui/core";
import React, { useEffect, useState } from "react";
export default function SocialCardsfunction() {
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(true);
const classes = useStyles();
const fetchPerson = () => {
fetch("https://randomuser.me/api")
.then((response) => response.json())
.then((response) => {
setTimeout(() => {
setItems(response.results);
setLoading(false);
}, 1000);
});
};
useEffect(() => {
fetchPerson();
}, []);
if (loading) {
return <div>Loading ...</div>;
} else {
return (
<div>
{items.map((item, i) => {
return (
<div key={i}>
<Card className={classes.root}>
<h2>{item.name.first}</h2>
<img
alt="img"
src={item.picture.large}
className={classes.large}
/>
<CardActions>
<Button onClick={() => fetchPerson()} size="small">Next</Button>
</CardActions>
</Card>
</div>
);
})}
</div>
);
}
}
const useStyles = makeStyles({
root: {
minWidth: 275
},
bullet: {
display: "inline-block",
margin: "0 2px",
transform: "scale(0.8)"
},
title: {
fontSize: 14
},
pos: {
marginBottom: 12
}
});
您的逻辑看起来不错,但总有一些可以进一步改进的地方。
如果您只想在SocialCard
中一次存储一个用户,那么我将只从 API 而不是列表中提取一个用户,因为 API 无论如何都会返回一个仅包含一个 ZA8CFDE6331BD59EB2AC96F8911C4B666 的数组。
首先,我将更改 state 并包括status
和error
。 使用status
,您可以轻松检查您的组件当前处于哪个状态,并根据该状态在您的应用程序中呈现不同的事物/消息。 使用error
,您可以定义自己的错误以防出现问题,然后在您的应用程序中呈现错误消息。 另外,我重新使用了您的 fetch,因为它被使用了两次,而且是多余的。 这样你就有了一个很好的单个 function 可以在任何地方使用,同时还确保在获取结果时显示loading
。 我还使用 MaterialUI Card
组件来呈现用户数据。 您可以在此处查看结果的样子
import React, { useState, useEffect } from "react";
import { makeStyles } from "@material-ui/core/styles";
import Card from "@material-ui/core/Card";
import CardActionArea from "@material-ui/core/CardActionArea";
import CardActions from "@material-ui/core/CardActions";
import CardContent from "@material-ui/core/CardContent";
import CardMedia from "@material-ui/core/CardMedia";
import Button from "@material-ui/core/Button";
import Typography from "@material-ui/core/Typography";
const useStyles = makeStyles({
root: {
maxWidth: 345
}
});
function App() {
const classes = useStyles();
const [state, setState] = useState({
user: {},
status: "idle",
error: null
});
const { user, status, error } = state;
const getUser = () => {
setState((prevState) => ({
...prevState,
status: "loading"
}));
fetch("https://randomuser.me/api").then(async (res) => {
if (res.ok) {
const data = await res.json();
setState((prevState) => ({
...prevState,
user: data.results[0],
status: "processed"
}));
} else {
setState({
user: {},
status: "failed",
error: "Error message"
});
}
});
};
useEffect(() => {
getUser();
}, []);
if (status === "loading") {
return <div>Loading ...</div>;
}
if (status === "failed") {
return <div>{error}</div>;
}
if (status === "processed") {
return (
<Card className={classes.root}>
<CardActionArea>
<CardMedia
component="img"
alt="user"
height="140"
image={user.picture.large}
title="user"
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
{user.name.first}
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button size="small" color="primary" onClick={getUser}>
Show another user
</Button>
</CardActions>
</Card>
);
} else {
// Default placeholder
return <div>hi</div>;
}
}
export default App;
但是,如果您想存储单击按钮时获取的所有用户,我建议将用户的 fetch 和 state 移动到父组件中,并保留SocialCard
组件仅用于呈现单个用户。 然后,在父组件中,我将确保setState
在getUser
function 中看起来像这样
setState((prevState) => ({
...prevState,
users: [...prevState.users, ...data.results], // This merges your previous user objects with new user object
status: "processed"
}));
这样,您可以将所有用户保留在父组件中,并使用map
您可以使用SocialCard
组件呈现每个用户。 请注意,您需要进一步重构组件才能使其正常工作。 如果您想使用 go 这条路线,我会将其作为练习留给您。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.