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

ra-data-hasura搭配React-Admin时getList失效 无法拆分posts端点的图片视频资源

问题根因说明

你之前的自定义逻辑不生效,是因为 ra-data-hasura 是基于GraphQL实现的数据源,而你写的getList是REST风格的URL拼接逻辑,完全不兼容,而且buildHasuraProvider的第二个参数也不是用来直接覆写数据源方法的,所以你的自定义代码根本不会被执行,自然还是会报端点不存在的错误。


可行解决方案

你需要先拿到ra-data-hasura生成的原生数据源实例,再包装一层重写你用到的所有资源方法,对images和videos资源做特殊的名称替换、条件过滤处理即可,代码示例如下:

import buildHasuraProvider from 'ra-data-hasura';
import { ApolloClient, InMemoryCache } from '@apollo/client';

function DashboardPage(props) {
  const [dataProvider, setDataProvider] = useState(null);

  useEffect(() => {
    const initDataProvider = async () => {
      const client = new ApolloClient({
        uri: process.env.NEXT_PUBLIC_HASURA_GRAPHQL_ENDPOINT,
        cache: new InMemoryCache(),
        headers: {
          'x-hasura-admin-secret': process.env.NEXT_PUBLIC_HASURA_GRAPHQL_API_KEY,
        },
      });
      // 先获取原生的hasura数据源实例
      const originalProvider = await buildHasuraProvider({ client });
      // 包装一层自定义逻辑
      const customDataProvider = {
        ...originalProvider,
        // 重写getList方法
        getList: (resource, params) => {
          if (resource === 'images' || resource === 'videos') {
            // 把资源名替换为posts
            const targetResource = 'posts';
            // 追加过滤条件:images仅取带image字段的post,videos仅取带video字段的post
            const customFilter = {
              ...params.filter,
              [resource === 'images' ? 'image' : 'video']: { _is_null: false }
            }
            // 调用原生方法请求posts接口
            return originalProvider.getList(targetResource, {
              ...params,
              filter: customFilter
            }).then(res => {
              // 可选:如果需要调整返回字段结构可以在这里处理,比如把image字段映射为前端要的url字段
              const processedData = res.data.map(post => ({
                id: post.id,
                url: post[resource === 'images' ? 'image' : 'video'],
                ...post
              }))
              return {
                data: processedData,
                total: res.total
              }
            })
          }
          // 其他资源走原生逻辑
          return originalProvider.getList(resource, params);
        },
        // 你用到的其他资源方法也要做同样的替换处理,比如getOne、update、create、delete
        getOne: (resource, params) => {
          if (resource === 'images' || resource === 'videos') {
            return originalProvider.getOne('posts', params).then(res => ({
              ...res,
              data: {
                id: res.data.id,
                url: res.data[resource === 'images' ? 'image' : 'video'],
                ...res.data
              }
            }))
          }
          return originalProvider.getOne(resource, params);
        },
        // update、create、delete方法按照你的业务需求同理替换资源名即可
      }
      setDataProvider(customDataProvider);
    }
    initDataProvider();
  }, [])

  if (!dataProvider) return <p>Loading...</p>;

  // Resource注册逻辑和你之前的写法完全一致,不需要修改
  return (
    <Admin 
      layout={MyLayout} 
      theme={theme} 
      dataProvider={dataProvider}
    >
      <Resource name="images"  {...images} icon={ImageIcon} />
      <Resource name="videos"  {...videos} icon={VideoIcon} />
      <Resource name="comments" {...comments} icon={ChatIcon} />
      <Resource name="users" {...users} icon={PeopleIcon} />
    </Admin>
  )
}

注意事项

  • 所有你业务中用到的资源方法都需要做对应的替换处理,比如你用到了删除功能就要重写delete方法,用到了编辑功能就要重写update方法,避免操作时还是用images/videos作为资源名请求接口报错。
  • 如果不需要调整返回的字段结构,数据映射的部分可以直接返回原生结果,不需要额外处理。
  • 如果需要实现images/videos的新增功能,在create方法里把前端提交的字段映射到posts对应的image/video字段即可。

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

相关产品推荐
方舟 Agent Plan

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

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