如何在 Next.js 中使用 SWR 立即刷新数据提要
How to refresh a data feed instantly using SWR in Next.js
我有一个表单组件,用户可以在其中输入评论,还有一个单独的组件可以映射并显示评论列表。提交评论时,它只会在页面丢失并重新获得焦点时显示。我怎样才能让它在提交时显示新评论而不必先失去焦点?
这是我的表单组件中的相关代码
import { useSWRConfig } from 'swr'
const { mutate } = useSWRConfig()
const postData = async (form) => {
setLoading(true);
await axios.post('/api/comments', form);
mutate('/api/comments');
setLoading(false);
}
根据文档https://swr.vercel.app/docs/mutation“您可以从 useSWRConfig() 挂钩中获取 mutate 函数,并使用通过调用 mutate(key)*"
相同的键
这是显示评论的组件:
const Comments = ({ postId }) => {
const { comments, loading, error } = useComments(postId)
if (error) return <div>An terror has occurred</div>;
if (loading) return <div>Loading comments</div>;
return (
<div className="flex flex-col w-full space-y-2">
{comments && comments[0].map((comment) => (
<Comment
id={comment._id}
key={comment._id}
date={comment.createdAt}
postId={comment._id}
comment={comment.comment}
name={comment.userData[0].name}
photoUrl={comment.userData[0].photoUrl}
/>
))}
</div>
)
}
这是我的 useComments 挂钩
export default function useComments (postId) {
const { data, mutate, error } = useSWR(`/api/comments/${postId}`, fetcher);
const loading = !data && !error;
const loggedOut = error && error.status === 403;
return {
loading,
loggedOut,
comments: data,
mutate,
error: error
}
}
非常非常感谢任何帮助。
mutate 函数实际上会重新验证缓存的结果,这意味着它会在您添加评论后向 API 发送另一个请求。您需要调用以下 mutate 函数。
import { useSWRConfig } from 'swr'
const { data, mutate, error } = useSWR(`/api/comments`, fetcher);
const postData = async (form) => {
setLoading(true);
await axios.post('/api/comments', form);
mutate('/api/comments', {...data, form});
setLoading(false);
}
顺便说一句,我假设 form
包含要保存在数据库中的 comment
对象。让我知道这是否有效。
已编辑
所以我为您找到了解决方案。我不知道它是否完美,但它完全符合您的要求。
第一个pages/api/comments/index.js
case "GET":
try {
const { db } = await connectToDatabase();
const comments = await
db.collection("comments").find({}).toArray();
res.status(200).json({ comments });
} catch (error) {
console.log(error);
}
break;
我们在评论对象中返回一个对象数组。
然后在 pages/index.js
文件中:
import Form from "../components/comment-form";
import Comments from "../components/comments";
import useSWR from "swr";
import fetcher from "../libs/fetcher";
export default function IndexPage() {
const { data, mutate } = useSWR(`/api/comments`, fetcher);
return (
<>
<div>hello</div>
<Form mutate={mutate} />
<Comments comments={data?.comments} />
</>
);
}
我们在这里定义 useSWR 挂钩。我们只从这里传递 mutate 对象。
然后components/comments.js
文件
import Comment from "./comment";
const Comments = ({ comments }) => {
if (!comments) return <div>Loading comments</div>;
return (
<div>
<span>Comments</span>
{comments.map((comment, i) => (
<Comment key={i} comment={comment.comment} />
))}
</div>
);
};
export default Comments;
这里我们正在接收来自索引文件的评论。顺便说一下,这是SWR取数据的推荐方式。
终于在 components/comment-form.js
文件中
import { useState } from "react";
import axios from "axios";
const AddComment = ({ mutate }) => {
const [form, setForm] = useState({
comment: ""
});
const postData = async (form) => {
await axios.post("/api/comments", form);
await mutate();
//clear the form
setForm({ ...form, comment: "" });
};
const handleSubmit = (e) => {
e.preventDefault();
postData(form);
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={form.comment}
onChange={(e) => setForm({ ...form, comment: e.target.value })}
placeholder="Add a comment..."
/>
</form>
);
};
export default AddComment;
现在可以了。您可以在 sandbox-link
中找到工作代码示例
我真的希望这能解决你的问题。
我有一个表单组件,用户可以在其中输入评论,还有一个单独的组件可以映射并显示评论列表。提交评论时,它只会在页面丢失并重新获得焦点时显示。我怎样才能让它在提交时显示新评论而不必先失去焦点?
这是我的表单组件中的相关代码
import { useSWRConfig } from 'swr'
const { mutate } = useSWRConfig()
const postData = async (form) => {
setLoading(true);
await axios.post('/api/comments', form);
mutate('/api/comments');
setLoading(false);
}
根据文档https://swr.vercel.app/docs/mutation“您可以从 useSWRConfig() 挂钩中获取 mutate 函数,并使用通过调用 mutate(key)*"
相同的键这是显示评论的组件:
const Comments = ({ postId }) => {
const { comments, loading, error } = useComments(postId)
if (error) return <div>An terror has occurred</div>;
if (loading) return <div>Loading comments</div>;
return (
<div className="flex flex-col w-full space-y-2">
{comments && comments[0].map((comment) => (
<Comment
id={comment._id}
key={comment._id}
date={comment.createdAt}
postId={comment._id}
comment={comment.comment}
name={comment.userData[0].name}
photoUrl={comment.userData[0].photoUrl}
/>
))}
</div>
)
}
这是我的 useComments 挂钩
export default function useComments (postId) {
const { data, mutate, error } = useSWR(`/api/comments/${postId}`, fetcher);
const loading = !data && !error;
const loggedOut = error && error.status === 403;
return {
loading,
loggedOut,
comments: data,
mutate,
error: error
}
}
非常非常感谢任何帮助。
mutate 函数实际上会重新验证缓存的结果,这意味着它会在您添加评论后向 API 发送另一个请求。您需要调用以下 mutate 函数。
import { useSWRConfig } from 'swr'
const { data, mutate, error } = useSWR(`/api/comments`, fetcher);
const postData = async (form) => {
setLoading(true);
await axios.post('/api/comments', form);
mutate('/api/comments', {...data, form});
setLoading(false);
}
顺便说一句,我假设 form
包含要保存在数据库中的 comment
对象。让我知道这是否有效。
已编辑
所以我为您找到了解决方案。我不知道它是否完美,但它完全符合您的要求。
第一个pages/api/comments/index.js
case "GET":
try {
const { db } = await connectToDatabase();
const comments = await
db.collection("comments").find({}).toArray();
res.status(200).json({ comments });
} catch (error) {
console.log(error);
}
break;
我们在评论对象中返回一个对象数组。
然后在 pages/index.js
文件中:
import Form from "../components/comment-form";
import Comments from "../components/comments";
import useSWR from "swr";
import fetcher from "../libs/fetcher";
export default function IndexPage() {
const { data, mutate } = useSWR(`/api/comments`, fetcher);
return (
<>
<div>hello</div>
<Form mutate={mutate} />
<Comments comments={data?.comments} />
</>
);
}
我们在这里定义 useSWR 挂钩。我们只从这里传递 mutate 对象。
然后components/comments.js
文件
import Comment from "./comment";
const Comments = ({ comments }) => {
if (!comments) return <div>Loading comments</div>;
return (
<div>
<span>Comments</span>
{comments.map((comment, i) => (
<Comment key={i} comment={comment.comment} />
))}
</div>
);
};
export default Comments;
这里我们正在接收来自索引文件的评论。顺便说一下,这是SWR取数据的推荐方式。
终于在 components/comment-form.js
文件中
import { useState } from "react";
import axios from "axios";
const AddComment = ({ mutate }) => {
const [form, setForm] = useState({
comment: ""
});
const postData = async (form) => {
await axios.post("/api/comments", form);
await mutate();
//clear the form
setForm({ ...form, comment: "" });
};
const handleSubmit = (e) => {
e.preventDefault();
postData(form);
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={form.comment}
onChange={(e) => setForm({ ...form, comment: e.target.value })}
placeholder="Add a comment..."
/>
</form>
);
};
export default AddComment;
现在可以了。您可以在 sandbox-link
中找到工作代码示例我真的希望这能解决你的问题。