在组件中调用自定义 React 异步挂钩并再次设置它的状态

Call custom React async hook within a component and se it's state again

我有一个自定义的反应挂钩从 API 中获取评论数量,如下所示:

export async function useFetchNumberOfComments(articleId) {
  const [numberOfComments, setNumbeOfComments] = useState(0);

  useEffect(() => {
    (async () => {
      try {
        const response = await axios.get(`https://example.com/${articleId}`, {
          headers: {
            "Content-Type": "application/json",
            "X-API-KEY": "X",
            Authorization: localStorage.getItem("access_token"),
          },
        });

        const data = await response.data;

        setNumbeOfComments(data);
      } catch (err) {
        console.log(err);
      }
    })();
  }, []);

  return numberOfComments;
}

我想在文章组件中使用它,如下所示:

import { useFetchNumberOfComments } from "../utils";

const SingleArticle = () => {
  let { id } = useParams();
  // Important state
  const [numOfComments, setNumOfComments] = useState(0);
  // Not important states
  const [title, setTitle] = useState("");
  const [author, setAuthor] = useState("");
  const [content, setContent] = useState("");
  const [comments, setComments] = useState([]);
  const [commentAuthor, setCommentAuthor] = useState("");
  const [commentContent, setCommentContent] = useState("");
  const [imageId, setImageId] = useState("");
  const [imageUrl, setImageUrl] = useState("");
  const [createdAt, setCreatedAt] = useState();

  const postComment = async (e) => {
    e.preventDefault();

    const dataToSend = {
      articleId: id,
      author: commentAuthor,
      content: commentContent,
    };

    try {
      await axios.post(`https://example.com/comments`, dataToSend, {
        headers: {
          "Content-Type": "application/json",
          "X-API-KEY": "X",
          Authorization: localStorage.getItem("access_token"),
        },
      });

      
      // Here, fetch the number of comments from my custom hook and update numOf Comments in this component
      setCommentAuthor("");
      setCommentContent("");
    } catch (err) {
      console.log(err);
    }
  };

  return (
    <>
      <form onSubmit={postComment}>
        // Here are some inputs, labels and a submit button
      </form>  
      <h4 className={styles.h1}>Comments({numOfComments})</h4>
    </>
  );
};

export default SingleArticle;

现在,问题是我不知道如何在 Article 组件中执行提到的 activity:发送表单数据(用于评论)后,触发 useFetchNumberOfComments 自定义挂钩并将文章组件中的 numOfComments 状态设置为新获取的数据。

我认为您最好将 useFetchNumberOfComments 钩子重构为 return 获取函数和一些获取请求元数据,即加载和响应以及错误状态。

示例:

export function useFetchNumberOfComments() {
  const [numberOfComments, setNumbeOfComments] = useState(0);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const fetchArticleCommentCount = useCallback(async (articleId) => {
    setLoading(true);
    try {
      const response = await axios.get(`https://example.com/${articleId}`, {
        headers: {
          "Content-Type": "application/json",
          "X-API-KEY": "X",
          Authorization: JSON.parse(localStorage.getItem("access_token")),
        },
      });

      const data = await response.data;

      setNumbeOfComments(data);
      setError(null);

      return data;
    } catch (err) {
      console.log(err);
      setError(err);
    } finally {
      setLoading(false);
    }
  }, []);
  
  return {
    fetchArticleCommentCount,
    numberOfComments,
    loading,
    error
  };
};

...

import { useFetchNumberOfComments } from "../utils";

const SingleArticle = () => {
  const { id } = useParams();

  const {
    fetchArticleCommentCount,
    numberOfComments,
  } = useFetchNumberOfComments();

  // Important state
  const [numOfComments, setNumOfComments] = useState(0);

  // Not important states
  ...

  const postComment = async (e) => {
    e.preventDefault();

    const dataToSend = {
      articleId: id,
      author: commentAuthor,
      content: commentContent,
    };

    try {
      await axios.post(`https://example.com/comments`, dataToSend, {
        headers: {
          "Content-Type": "application/json",
          "X-API-KEY": "X",
          Authorization: localStorage.getItem("access_token"),
        },
      });

      // await returned comment count and update local state
      const commentCount = await fetchArticleCommentCount(id);
      setNumOfComments(commentCount);

      // or use the updated numberOfComments value returned from hook
      fetchArticleCommentCount(id);
      // both are available, but you only need one or the other here

      setCommentAuthor("");
      setCommentContent("");
    } catch (err) {
      console.log(err);
    }
  };

  return (
    <>
      <form onSubmit={postComment}>
        // Here are some inputs, labels and a submit button
      </form>  
      <h4 className={styles.h1}>Comments({numberOfComments})</h4>
    </>
  );
};

export default SingleArticle;