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

React Admin编辑记录时发自定义查询:CameraEdit预览功能实现疑问

问题1:在React Admin中发起额外异步查询

React Admin不限制你使用普通React项目的异步请求方案,有两种常用方式可选:

  • 直接用项目中已配置的GraphQL客户端(比如Apollo Client)的useLazyQuery hook,用法和普通React项目完全一致
  • 如果你已经适配了GraphQL的dataProvider,也可以用React Admin官方提供的useDataProvider hook发起请求

问题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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 17:36:01