[英]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.