React Admin编辑记录时发自定义查询:CameraEdit预览功能实现疑问
问题1:在React Admin中发起额外异步查询
React Admin不限制你使用普通React项目的异步请求方案,有两种常用方式可选:
- 直接用项目中已配置的GraphQL客户端(比如Apollo Client)的
useLazyQueryhook,用法和普通React项目完全一致 - 如果你已经适配了GraphQL的dataProvider,也可以用React Admin官方提供的
useDataProviderhook发起请求
问题2:下载返回的图片资源
拿到后端返回的图片URL/二进制流后,只需要构造临时a标签触发点击即可实现自动下载,代码逻辑如下:
const downloadImage = (url: string, fileName = 'preview.jpg') => { const a = document.createElement('a'); a.href = url; a.download = fileName; a.click(); }
如果返回的是二进制流,先通过URL.createObjectURL(blob)把流转为可访问的url再调用上面的方法即可。
问题3:在SimpleForm中添加非输入组件
你提到的“SimpleForm仅支持直接放置输入类组件”是错误认知,SimpleForm本质是对表单容器的封装,支持放置任意React组件,非输入组件不会被纳入表单字段收集逻辑,完全不影响正常使用。你可以用MUI的Grid等布局组件实现表单和预览区的左右排布。
完整实现代码
import { useState } from 'react'; import { useLazyQuery, gql } from '@apollo/client'; import { Edit, SimpleForm, TextInput, Button, useRecordContext } from 'react-admin'; import { Grid, Box, Typography } from '@mui/material'; import type { FC } from 'react'; import type { ResourceComponentProps } from 'react-admin'; // 替换为你实际的预览查询语句 const GET_CAMERA_PREVIEW = gql` query GetCameraPreview($connection: String!) { cameraPreview(connection: $connection) { imageUrl } } `; export const CameraEdit: FC<ResourceComponentProps> = (props) => { const [previewUrl, setPreviewUrl] = useState<string | null>(null); const record = useRecordContext(); const [fetchPreview, { loading }] = useLazyQuery(GET_CAMERA_PREVIEW, { onCompleted: (data) => { const imgUrl = data.cameraPreview.imageUrl; setPreviewUrl(imgUrl); // 自动下载图片,不需要可以删除这段 const a = document.createElement('a'); a.href = imgUrl; a.download = `${record?.name || 'camera'}-preview.jpg`; a.click(); } }); const handlePreviewClick = () => { if (!record?.connection) return; fetchPreview({ variables: { connection: record.connection } }); }; return ( <Edit {...props}> <SimpleForm> <Grid container spacing={4}> {/* 左侧表单区域 */} <Grid item xs={12} md={6}> <TextInput source="name" fullWidth /> <TextInput source="connection" fullWidth sx={{ my: 2 }} /> <Button variant="contained" label={loading ? '加载中' : 'Preview'} onClick={handlePreviewClick} disabled={!record?.connection || loading} /> </Grid> {/* 右侧预览区域 */} <Grid item xs={12} md={6}> <Box> <Typography variant="h6" mb={2}>预览图</Typography> {previewUrl ? ( <img src={previewUrl} alt="相机预览" style={{ maxWidth: '100%', maxHeight: '500px', border: '1px solid #eee', borderRadius: '4px' }} /> ) : ( <Typography color="text.secondary">点击Preview按钮加载预览</Typography> )} </Box> </Grid> </Grid> </SimpleForm> </Edit> ); };
补充说明
- 如果后端返回的是二进制图片流,需要在请求的时候指定响应类型为blob,再通过
URL.createObjectURL(blob)生成可访问的图片地址 - 如果你不想用Apollo的hook,替换为用
useDataProvider发起请求也可以,只需要把请求逻辑替换为dataProvider的调用即可
内容的提问来源于stack exchange,提问作者koral
相关产品推荐
相关产品推荐

