如何在 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

中找到工作代码示例

我真的希望这能解决你的问题。