React 更干净的 API 调用

62 阅读1分钟

背景

我们常常需要请求接口数据,用在页面上展示 比如这样

import axios from "axios";
import { useEffect, useState } from "react";
import { useParams } from "react-router";

import { Loading } from "../components/Loading";
import { Post } from "../components/Post";
import { Comments } from "../components/Comments";

export function PostWithComments() {
  const { postId } = useParams();

  const [post, setPost] = useState();
  const [comments, setComments] = useState();
  const [error, setError] = useState(false);

  useEffect(() => {
    axios
      .get(`https://jsonplaceholder.typicode.com/posts/${postId}`)
      .then((response) => setPost(response.data))
      .catch(() => setError(true));

    axios
      .get(`https://jsonplaceholder.typicode.com/comments?postId=${postId}`)
      .then((response) => setComments(response.data))
      .catch(() => setError(true));
      
  }, [postId]);

  if (error) {
    return <div>Oops, an error occurred</div>;
  }
  
  if (!post || !postComments) {
    return <Loading />;
  }

  return (
    <section className="post-with-comments">
      <Post post={post.data} />
      <Comments comments={comments.data} />
    </section>
  );
}

看起来没啥问题,但如果项目当中有更多的 axios 轻轻,并且 url 前缀都是一样的,之后怎么维护?

axios
      .get(`https://jsonplaceholder.typicode.com/posts/${postId}`)
      .then((response) => setPost(response.data))
      .catch(() => setError(true));

axios
      .get(`https://jsonplaceholder.typicode.com/comments?postId=${postId}`)
      .then((response) => setComments(response.data))
      .catch(() => setError(true));

优化

使用 client.js

import axios from "axios";

export const client = axios.create({
  baseURL: "https://jsonplaceholder.typicode.com",
});

使用时 就可直接导入这个 client

import { client } from "../api/client";
...

export function PostWithComments() {
 ...

  useEffect(() => {
    client
      .get(`/posts/${postId}`)
      .then((response) => setPost(response.data))
      .catch(() => setError(true));

    client
      .get(`/comments?postId=${postId}`)
      .then((response) => setComments(response.data))
      .catch(() => setError(true));
      
  }, [postId]);

  ...
}

看起来简洁很多,并且如果 url 前缀需要改变,直接去改 client.js 就可以了

不过 还有个问题,这里必须 明确写 .get 或 .post 请求类型,这部分能不能再优化下

再优化

单独函数中隔离 API 调用

import { client } from "./client";

async function getPost(postId: string) {
  const response = await client.get(
    `/posts/${postId}`
  );
  return response.data;
}

async function getComments(postId: string) {
  const response = await apiClient.get(
    `/comments?postId=${postId}`
  );
  return response.data;
}

export default { getPost, getComments };

这样就可以 直接 使用函数的方式 来调用,而不再需要 单独写

import PostApis from "../api/post";
...

export function PostWithComments() {
  const { postId } = useParams();

  const [post, setPost] = useState();
  const [comments, setComments] = useState();
  const [error, setError] = useState(false);

  useEffect(() => {
    PostApis.getPost(postId)
      .then((response) => setPost(response.data))
      .catch(() => setError(true));

    PostApis.getComments(postId)
      .then((response) => setComments(response.data))
      .catch(() => setError(true));
      
  }, [postId]);

  ...
}

这样就更好了