React - 使用钩子重构逻辑

React - Refactoring logic with hooks

简介

我有一个向我的服务器查询的屏幕:

  1. 通过用户名获取用户(当用户在搜索输入中输入内容时)

  2. 获取高级用户(挂载屏幕时 + 下拉刷新)

  3. 获取年轻用户(挂载屏幕时 + 拉动刷新)

我正在考虑将其移到钩子上。

这是我当前的代码:

function MyScreen() {
   // Fetch by username
   const [isSearching, setIsSearching] = useState([]);
   const [searchedUsers, setSearchedUsers] = useState([]);


   // Premium
   const [isLoading, setIsLoading] = useState(true); <--- NOTE THIS 
   const [premiumUsers, setPremiumUsers] = useState([]);

   // Young users
   const [youngUsers, setYoungUsers] = useState([]);


   /*
       FIRST METHOD
   */
   const searchUsersByUsername = async (limit = 20) => {
      setIsSearching(true);

      try {
         const result = await api.users.searchUsersByUsername(username, limit);
         setSearchedUsers(result);
      } catch(err) {
         console.log(err);
      }

      setIsSearching(false);
   }

   /*
       SECOND METHOD
   */
   const getPremiumUsers = async (limit = 10) => {
      // Note: No loading here
      try {
         const result = await api.users.getPremiumUsers(limit);
         setPremiumUsers(result);
      } catch(err) {
         console.log(err);
      }
   }


   /*
       THIRD METHOD
   */
   const getYoungUsers = async (limit = 10) => {
      // Note: No loading here
      try {
         const result = await api.users.getYoungUsers(limit);
         setYoungUsersUsers(result);
      } catch(err) {
         console.log(err);
      }
   }



   // Effects and rendering...   

   useEffect(() => {
      (async () => {
         const promises = [getPremiumUsers(), getYoungUsers()];

         await Promise.all(promises).catch((err) => {
            console.log(err))
         });

         setIsLoading(false); // <---- NOTE THIS
      })();
      
   }, []);      

}

问题

我无法使用典型的 useQuery 挂钩,因为我正在使用 Firestore 可调用函数。因此,发出请求的唯一方法是调用我的 api 方法 (api.users.searchUser...)

正如你在代码中看到的,我有两种加载指示器(两种状态):

  1. isSearching(用于按用户名搜索功能)

  2. isLoading(用于并行获取高级用户和年轻用户

如何为这个逻辑实现可重用的钩子?

我的意思是,我需要抽象所有这些东西,以便能够:

  1. 在其他页面按用户名搜索用户

  2. 搜索高级用户(不并行获取年轻用户)

  3. 搜索年轻用户(不并行获取高级用户)

同时,获取三个查询的加载状态。

注意:在我当前的屏幕中,正如我之前所说,我正在为年轻和高级用户使用“setIsLoading”并行 抓取,但也许(为了更灵活) 在其他屏幕中,我将独立需要每个逻辑的加载状态。

有什么帮助或想法吗?

您可以通过每个获取方法使用 React.useEffectReact.useCallback。 另外,单独保存加载状态。

看看这个:

import { useEffect, useCallback } from 'react';

const defaultParams = {
  fetchPremiumUsersOnMount: false,
  fetchYoungUsersOnMount: false,
  searchOnMount: false,
  username: '',
  limit: 20,
}

function useUsersApi(params = defaultParams) {
   const [isSearching, setIsSearching] = useState(false);
   const [searchedUsers, setSearchedUsers] = useState([]);

   const [premiumUsers, setPremiumUsers] = useState([]);
   const [premiumLoading, setPremiumLoading] = useState(false);

   const [youngUsers, setYoungUsers] = useState([]);
   const [youngLoading, setYoungLoading] = useState(false);

  const fetchPremiumUsers = useCallback(async () => {
    try {
      setPremiumLoading(true);
      const result = api.users.getPremiumUsers(params.limit);
      setPremiumUsers(result);
    } catch (err) {
      console.log(err)
    } finally {
      setPremiumLoading(false);
    }
  }, [params.limit]);

  const fetchYoungUsers = useCallback(async () => {
    /* similar logic to `fetchPremiumUsers` */
  }, [params.limit, params.]);

  const fetchSearchUsers = useCallback(async (username) => {
    /* fetch logic here */
  }, [params.limit]);

   useEffect(() => {
     if(params.fetchPremiumUsersOnMount) {
       fetchPremiumUsers();
     }
   }, [params.fetchPremiumUsersOnMount, params.limit]); 


   useEffect(() => {
     if(params.fetchYoungUsersOnMount) {
       fetchYoungUsers();
     }
   }, [params.fetchYoungUsersOnMount, params.limit]); 

   useEffect(() => {
     if(params.fetchSearchUsers) {
       fetchSearchUser(params.username);
     }
   }, [params.searchOnMount, params.limit, params.username]); 


  return {
    isSearching,
    searchedUsers,
    isLoading: premiumLoading || youngLoading,
    premiumUsers,
    premiumUsersLoading: premiumLoading,
    refreshPremiumUsers: fetchPremiumUsers,
    youngUsers,
    youngUsersLoading: youngLoading,
    refreshYoungUsers: fetchYoungUsers,
  }
}