我是Next js的新手,我想在useEffect
中调用news api,并将新闻数组分发到我的商店。然后根据用户在标题搜索栏中的输入进行过滤。问题是,一旦完成使用效果数据的提取并且用户开始键入而不是过滤新闻数组,屏幕将重新呈现,并且数据提取将再次开始。如何防止这种重新渲染并保存新闻数组?
我尝试使用getStaticprops
,但是那里不允许使用useDispatch。
index.js
import { fetchNews } from "../store/actions/newsActions";
import NewsInfo from "../components/NewsInfo";
import { useDispatch, useSelector } from "react-redux";
import CircularProgress from "@material-ui/core/CircularProgress";
export default function Home() {
const dispatch = useDispatch();
const { news } = useSelector((state) => state.news);
React.useEffect(() => {
dispatch(fetchNews());
}, []);
return (
<>
{/* this wrapper cmp will make each headline uniquely accessible */}
{news?.articles ? (
news.articles.map((article) => (
<React.Fragment key={article.publishedAt}>
<NewsInfo headlines={article} />
</React.Fragment>
))
) : (
<CircularProgress />
)}
</>
);
}
Header.js
import React from "react";
import AppBar from "@material-ui/core/AppBar";
import Toolbar from "@material-ui/core/Toolbar";
import IconButton from "@material-ui/core/IconButton";
import Typography from "@material-ui/core/Typography";
import InputBase from "@material-ui/core/InputBase";
import { fade, makeStyles } from "@material-ui/core/styles";
import MenuIcon from "@material-ui/icons/Menu";
import SearchIcon from "@material-ui/icons/Search";
import { useDispatch } from "react-redux";
import { filterHeadlines } from "../store/actions/newsActions";
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
},
menuButton: {
marginRight: theme.spacing(2),
},
title: {
flexGrow: 1,
display: "none",
[theme.breakpoints.up("sm")]: {
display: "block",
},
},
search: {
position: "relative",
borderRadius: theme.shape.borderRadius,
backgroundColor: fade(theme.palette.common.white, 0.15),
"&:hover": {
backgroundColor: fade(theme.palette.common.white, 0.25),
},
marginLeft: 0,
width: "100%",
[theme.breakpoints.up("sm")]: {
marginLeft: theme.spacing(1),
width: "auto",
},
},
searchIcon: {
padding: theme.spacing(0, 2),
height: "100%",
position: "absolute",
pointerEvents: "none",
display: "flex",
alignItems: "center",
justifyContent: "center",
},
inputRoot: {
color: "inherit",
},
inputInput: {
padding: theme.spacing(1, 1, 1, 0),
// vertical padding + font size from searchIcon
paddingLeft: `calc(1em + ${theme.spacing(4)}px)`,
transition: theme.transitions.create("width"),
width: "100%",
[theme.breakpoints.up("sm")]: {
width: "12ch",
"&:focus": {
width: "20ch",
},
},
},
}));
function SearchAppBar() {
const classes = useStyles();
const dispatch = useDispatch();
const [input, setInput] = React.useState("");
return (
<div className={classes.root}>
<AppBar position="static">
<Toolbar>
<IconButton
edge="start"
className={classes.menuButton}
color="inherit"
aria-label="open drawer"
>
<MenuIcon />
</IconButton>
<Typography className={classes.title} variant="h6" noWrap>
Material-UI
</Typography>
<div className={classes.search}>
<div className={classes.searchIcon}>
<SearchIcon />
</div>
<InputBase
placeholder="Search…"
classes={{
root: classes.inputRoot,
input: classes.inputInput,
}}
inputProps={{ "aria-label": "search" }}
value={input}
onChange={(e) => setInput(e.target.value)}
onBlur={() => dispatch(filterHeadlines(input))}
/>
</div>
</Toolbar>
</AppBar>
</div>
);
}
export default SearchAppBar;