You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何封装自定义React Hook实现Apollo Client查询与Mutation逻辑复用

基于Apollo Client的可复用CRUD自定义Hook实现

React Hook只能在函数组件或其他自定义Hook内部调用,将公共CRUD逻辑封装为自定义Hook,可变配置通过入参传入,即可实现全页面复用。

步骤1:封装通用CRUD自定义Hook

import { useQuery, useMutation, useMemo } from '@apollo/client'
import { notification } from 'antd' // 替换为你项目使用的提示组件即可

/**
 * 通用Apollo CRUD操作Hook
 * @param {Object} config 配置项
 * @param {DocumentNode} config.searchQuery 列表查询GQL语句
 * @param {DocumentNode} config.createMutation 新增GQL语句
 * @param {DocumentNode} [config.updateMutation] 更新GQL语句(可选)
 * @param {DocumentNode} [config.deleteMutation] 删除GQL语句(可选)
 * @param {Object} config.variables 查询/突变默认携带的公共变量(如profileId)
 * @param {Object} [config.tips] 各操作成功提示文案(可选,可覆盖默认值)
 */
const useCrudOperations = (config) => {
  const {
    searchQuery,
    createMutation,
    updateMutation,
    deleteMutation,
    variables = {},
    tips = {
      addSuccess: '新增成功',
      updateSuccess: '更新成功',
      deleteSuccess: '删除成功'
    }
  } = config

  // 列表查询逻辑
  const {
    data: listData,
    loading: queryLoading,
    error: queryError,
    refetch: refetchList
  } = useQuery(searchQuery, { variables })

  // 新增突变逻辑
  const [addRow, {
    loading: addLoading,
    error: addError
  }] = useMutation(createMutation, {
    refetchQueries: [{ query: searchQuery, variables }],
    onCompleted: () => {
      notification.success({
        message: '操作成功',
        description: tips.addSuccess
      })
    }
  })

  // 更新突变逻辑(可选)
  const [updateRow, {
    loading: updateLoading,
    error: updateError
  }] = updateMutation ? useMutation(updateMutation, {
    refetchQueries: [{ query: searchQuery, variables }],
    onCompleted: () => {
      notification.success({
        message: '操作成功',
        description: tips.updateSuccess
      })
    }
  }) : [() => {}, { loading: false, error: null }]

  // 删除突变逻辑(可选)
  const [deleteRow, {
    loading: deleteLoading,
    error: deleteError
  }] = deleteMutation ? useMutation(deleteMutation, {
    refetchQueries: [{ query: searchQuery, variables }],
    onCompleted: () => {
      notification.success({
        message: '操作成功',
        description: tips.deleteSuccess
      })
    }
  }) : [() => {}, { loading: false, error: null }]

  // 合并所有loading状态,替代页面单独写useEffect
  const globalLoading = useMemo(() => {
    return queryLoading || addLoading || updateLoading || deleteLoading
  }, [queryLoading, addLoading, updateLoading, deleteLoading])

  // 暴露给页面的返回值
  return {
    // 数据
    listData,
    queryError,
    addError,
    updateError,
    deleteError,
    globalLoading,
    // 方法
    addRow,
    updateRow,
    deleteRow,
    refetchList
  }
}

export default useCrudOperations

步骤2:页面中直接调用使用

不需要再写重复的查询、突变、loading合并逻辑,只需要传入对应GQL和变量即可:

// 页面组件内部
import useCrudOperations from '@/hooks/useCrudOperations'
import { SEARCH_ALL_ITEMS, CREATE_ITEMS, UPDATE_ITEMS, DELETE_ITEMS } from './gql'

const DemoPage = () => {
  const profileId = 'xxx' // 你的业务变量
  // 直接调用Hook获取所有需要的能力
  const {
    listData,
    globalLoading,
    addRow,
    updateRow,
    deleteRow
  } = useCrudOperations({
    searchQuery: SEARCH_ALL_ITEMS,
    createMutation: CREATE_ITEMS,
    updateMutation: UPDATE_ITEMS,
    deleteMutation: DELETE_ITEMS,
    variables: { profileId },
    tips: {
      addSuccess: '信息新增成功'
    }
  })

  // 页面内直接调用addRow等方法即可,不用再单独处理refetch、提示、loading
  const handleAdd = (formData) => {
    addRow({ variables: formData })
  }

  return <div>
    {/* 你的业务渲染逻辑 */}
  </div>
}

可扩展说明

  • 如果需要自定义onCompleted/onError逻辑,可以在Hook的入参里增加对应回调参数,优先级高于默认逻辑即可
  • 如果有懒查询需求,可以在Hook中增加useLazyQuery的封装逻辑,和上述思路一致
  • 所有内置的默认配置都支持通过入参覆盖,适配不同页面的个性化需求

内容的提问来源于stack exchange,提问作者WildThing

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 18:06:03