我有一个 React 18 应用程序。我正在使用
@tanstack/react-query
,版本 5 进行状态管理。
首先,当我点击“喜欢”按钮时,我的用户界面没有改变。典型的行为应该是点赞数应该增加一个。
其次,当我重新加载页面时,我的浏览器控制台中出现以下错误,并且我的浏览器视图为空白。
不确定,我在这里做错了什么。
下面是我的代码:
App.jsx
文件:
import { useState } from "react";
import MenuBar from "./components/MenuBar";
import Notification from "./components/Notification";
import BlogsPage from "./pages/BlogsPage";
import LoginPage from "./pages/LoginPage";
import UsersPage from "./pages/UsersPage";
import { Route, Routes, useMatch } from "react-router-dom";
import User from "./components/User";
import { useQueryClient } from "@tanstack/react-query";
import Blog from "./components/Blog";
const App = () => {
const queryClient = useQueryClient();
const allBlogs = queryClient.getQueryData(['blogs']);
const allUsers = queryClient.getQueryData(['users']);
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const userMatch = useMatch("/users/:id");
console.log('userMatch', userMatch);
const singleUserInfo = userMatch
? allUsers.find(user => user.id === userMatch.params.id)
: null;
console.log('singleUserInfo', singleUserInfo);
const blogMatch = useMatch("/blogs/:id");
console.log('blogMatch', blogMatch);
const singleBlogInfo = blogMatch
? allBlogs.find(blog => blog.id === blogMatch.params.id)
: null;
console.log('singleBlogInfo', singleBlogInfo);
return (
<div>
<h1>Blogs App</h1>
<MenuBar setUsername={setUsername} setPassword={setPassword} />
<Notification />
<LoginPage
username={username}
password={password}
setUsername={setUsername}
setPassword={setPassword}
/>
<Routes>
<Route path="/users/:id" element={<User user={singleUserInfo} />} />
<Route path="/blogs/:id" element={<Blog blog={singleBlogInfo} />} />
<Route path="/users" element={<UsersPage />} />
<Route path="/" element={<BlogsPage />} />
</Routes>
</div>
);
};
export default App;
Blog.jsx
文件:
import PropTypes from "prop-types";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useNotificationDispatch } from "../context/NotificationContext";
import blogService from "../services/blogs";
import { removeNotificationAfterFiveSeconds, setNotification } from "../helper/notificationSetOrRemove";
import { useUserValue } from "../context/UserContext";
import { Link } from "react-router-dom";
const Blog = ({ blog }) => {
console.log('Blog.jsx', blog);
const queryClient = useQueryClient();
const notificationDispatch = useNotificationDispatch();
const userLoggedIn = useUserValue();
const updateBlogMutation = useMutation({
mutationFn: blogService.updateBlog,
// mutationFn: (blog) => blogService.updateBlog(blog),
onSuccess: (updatedBlog) => {
// queryClient.invalidateQueries('blogs');
queryClient.invalidateQueries({ queryKey: ['blogs'] }, updatedBlog);
},
onError: (error, blogData) => {
console.error(`UPDATE MUTATION ERROR: ${error.message}`);
setNotification(notificationDispatch, `UPDATE MUTATION ERROR: Blog '${blogData.title}' was already removed from server`, true);
removeNotificationAfterFiveSeconds(notificationDispatch);
}
});
const handleIncreaseLikes = () => {
updateBlogMutation.mutate({ ...blog, likes: blog.likes + 1 });
};
return (
<div>
<h1 data-testid="title">{blog.title}</h1>
<h4 data-testid="author">Author: {blog.author}</h4>
<div data-testid="url">
<Link to={blog.url} target="_blank">{blog.url}</Link>
</div>
<div>
<div>
<div>
<span data-testid="likes">Likes: {blog.likes}</span>
<button onClick={handleIncreaseLikes} className="likeBtn">
like
</button>
</div>
<div data-testid="addedBy">Added by: {blog.user.name}</div>
</div>
</div>
</div>
);
};
Blog.propTypes = {
blog: PropTypes.shape({
id: PropTypes.string,
title: PropTypes.string.isRequired,
author: PropTypes.string.isRequired,
url: PropTypes.string.isRequired,
likes: PropTypes.number,
user: PropTypes.shape({
id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
username: PropTypes.string.isRequired,
}),
}),
};
export default Blog;
/src/services/blogs.js
文件:
import axios from 'axios';
const baseUrl = '/api/blogs';
const updateBlog = async (updatedBlog) => {
const response = await axios.put(`${baseUrl}/${updatedBlog.id}`, updatedBlog);
return response.data;
};
export default { updateBlog };
useQueryClient
不会对任何查询数据更改做出反应。标准方法是调用 useQuery
来检索任何数据(自动处理缓存)。
const allBlogs = useQuery({
queryKey: ['blogs'],
queryFn: () => {/* make request to get blog data*/}
}).data;