如何在 Next.js 中使用 SWR 立即刷新数据源

Mat*_*ton 1 reactjs next.js swr

我有一个表单组件,用户可以在其中输入评论,还有一个单独的组件,可以映射并显示评论列表。提交评论后,只有在页面失去焦点然后重新获得焦点时才会显示评论。我怎样才能让新评论在提交时显示出来而不必首先失去焦点?

这是我的表单组件中的相关代码

import { useSWRConfig } from 'swr'
const { mutate } = useSWRConfig()
const postData = async (form) => {
    setLoading(true);
    await axios.post('/api/comments', form);
    mutate('/api/comments');
    setLoading(false);
}
Run Code Online (Sandbox Code Playgroud)

根据文档https://swr.vercel.app/docs/mutation您可以从 useSWRConfig() 挂钩获取 mutate 函数,并通过调用 mutate(key) 使用相同的密钥向其他 SWR 挂钩全局广播重新验证消息)*"

这是显示评论的组件:

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>
)
}
Run Code Online (Sandbox Code Playgroud)

这是我的 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
    }
}
Run Code Online (Sandbox Code Playgroud)

非常非常感谢任何帮助。

Pra*_*nta 5

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);
    }

Run Code Online (Sandbox Code Playgroud)

顺便说一句,我假设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;

Run Code Online (Sandbox Code Playgroud)

我们在注释对象内返回一个对象数组。

然后在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} />
        </>
      );
    }

Run Code Online (Sandbox Code Playgroud)

我们在这里定义 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;

Run Code Online (Sandbox Code Playgroud)

在这里我们收到来自索引文件的注释。顺便说一句,这是通过 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;

Run Code Online (Sandbox Code Playgroud)

现在这会起作用了。您可以在此沙箱链接中找到工作代码示例

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