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
相关产品推荐
相关产品推荐

