【问题标题】:React Hooks - useFetch generalizationReact Hooks - useFetch 泛化
【发布时间】:2021-12-07 04:14:41
【问题描述】:

我有一个 api,它为我提供如下方法:

  1. searchUsersByUsername(用户名,限制)
  2. getRandomPremiumUsers(limit)
  3. getYoungUsers(maxAge, limit)

我正在实现一个钩子“useFetchUsers”,它将提供一个接口来访问这些方法。

这是我当前的代码:

import { useState, useEffect } from "react";

import {
  searchUsersByUsername, 
  getRandomPremiumUsers,
  getRandomYoungUsers,
} from "../../services/firebase/api/users/search"
import { MAX_SEARCH_USERS_BY_USERNAME_TO_RETRIEVE } from "../../utils/search";

export const QUERIES = {
  "SEARCH_USERS_BY_USERNAME": searchUsersByUsername,
  "FETCH_RANDOM_PREMIUM_USERS": getRandomPremiumUsers,
  "FETCH_RANDOM_YOUNG_USERS": getRandomYoungUsers,
};

const defaultOptions = {
  query: QUERIES[0],
  username: "", // optional
  limit = MAX_SEARCH_USERS_BY_USERNAME_TO_RETRIEVE, // optional
};

export default function useFetchUsers(options = defaultOptions, deps) {
  const [users, setUsers] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(undefined);

  const getUsers = async () => {
    setIsLoading(true);

    try {
      const users = await options.query();
      setUsers(users);
    } catch(err) {
      setError(err);
    }

    setIsLoading(false);
  }

  useEffect(getUsers, deps);

  return {
    users,
    isLoading,
    error,
    getUsers
  }
}

我面临的主要问题是,我不知道如何使这个“接口”更灵活,以便能够将参数传递给我的 QUERY 方法。

此外,我的 defaultOptions 对象不需要“getRandomPremiumUsers”和“getRandomYoungUsers”方法的字段“用户名”。

关于如何满足类似抽象的需求的任何想法?

【问题讨论】:

  • 你想在这里达到什么目的:useEffect(getUsers, deps);?
  • 你的问题太宽泛了,试试看能否在你的项目中使用 react-query。此外,有多种方法可以实现它。只需创建方法来获取数据并返回它。所以你可以通过任何方式打电话。
  • @SinanYaman 在必要时获取组件挂载
  • @ChandraKumar 我不能使用 react-query。
  • 我也想过为每个方法创建独立的钩子,但在某种程度上,由于它们是相关的概念,我认为将所有东西抽象在一个钩子中是一个更好的主意。

标签: javascript reactjs react-native design-patterns react-hooks


【解决方案1】:

创建方法并返回

export default function useFetchUsers() {
  const initialState = {
    payload: null,
    error: null,
    inFlight: false,
  };
  const [result, setResult] = useState(initialState);
  const searchUsersByUsername = () => {
    setResult({ payload: null, error: null, inFlight: true });
    try {
      const payload = fetch("api");
      setResult({ payload, error: null, inFlight: false });
    } catch (error) {
      setResult({ payload: null, error: null, inFlight: false });
    }
  };
  return {
    ...result,
    searchUsersByUsername,
  };
}

编写实现获取逻辑的 API 助手

const api = {
  user: {
    searchUsersByUsername: (option) => {
      return fetch(option);
    },
    getRandomPremiumUsers: (option) => {
      return fetch(option);
    },
    getYoungUsers: (option) => {
      return fetch(option);
    },
  },
};

export default function useFetchUsers() {
  const initialState = {
    payload: null,
    error: null,
    inFlight: false,
  };
  const [result, setResult] = useState(initialState);
  
  const updateState = (fetcher, option) => {
    setResult({ payload: null, error: null, inFlight: true });
    try {
      const payload = fetcher(option);
      setResult({ payload, error: null, inFlight: false });
    } catch (error) {
      setResult({ payload: null, error: null, inFlight: false });
    }
  };
  return {
    ...result,
    updateState,
  };
}

function App() {
  const { updateState, payload } = useFetchUsers();
  return (
    <div
      onclick={() =>
        updateState(api.user.searchUsersByUsername, { username: 'name', limit: 10 })
      }
    >
      searchUsersByUsername
    </div>
  );
}

因此,根据您的用例,您可以在 API 层本身中实现缓存或使用上下文 API 对其进行扩展

【讨论】:

  • 是的,我在api层实现了缓存! THX 老兄!
  • @ChandraKumar 我个人不喜欢钩子部分。我的意思是,你的钩子的目的不是“获取用户”,它只是一个使用给定选项调用“获取器”回调的函数,而不是“用户获取器”。感觉有些概念重叠(或者只是非常笼统)。
  • 抽象很棒,但有时它会使您的代码不像分解成小部分(模块)那样具有可读性。
  • @VictorMolina 这就是我在第一种方法中所做的。
猜你喜欢
  • 2020-01-26
  • 2020-01-25
  • 1970-01-01
  • 1970-01-01
  • 2019-11-08
  • 2019-11-06
  • 2019-09-30
  • 2020-10-11
  • 2021-04-19
相关资源
最近更新 更多