Remix.run中如何不通过表单实现点击图片时从服务端获取数据
Remix 无表单实现点击动态拉取服务端数据实现方案
你对action()、loader()的基础用途认知没问题,这俩API不是只能在页面初始加载、表单提交时触发,不用表单也能实现点击后按需拉取数据库数据,两种可直接落地的方案,适配你现有mongoose+query.server.ts的代码结构:
方案1:资源路由 + 客户端fetch(改造成本最低)
这个方案不需要改动你现有的页面代码逻辑,只需要加一个专门返回数据的接口路由即可:
- 新建资源路由文件
app/routes/api/image-data.$imageId.ts,资源路由不需要写前端组件,只导出服务端loader即可,在这里直接引入你封装在query.server.ts的查询方法,从路由参数里取图片ID查库,返回JSON格式数据:
// app/routes/api/image-data.$imageId.ts import type { LoaderFunctionArgs } from "@remix-run/node"; import { json } from "@remix-run/node"; import { queryImageById } from "~/utils/query.server"; // 你自己封装的数据库查询函数 export async function loader({ params }: LoaderFunctionArgs) { const targetId = params.imageId; if (!targetId) return json({ msg: "参数错误" }, { status: 400 }); const imageData = await queryImageById(targetId); return json(imageData); }
- 前端给图片绑定点击事件,点击时直接用原生
fetch请求上面的路由地址,拿到返回数据后做对应的UI更新(比如打开详情弹窗、填充侧边栏内容等)即可。不用担心query.server.ts的代码泄露到前端,.server.ts后缀的文件Remix在构建时只会打包到服务端产物里,不会出现在用户浏览器加载的JS里。
前端点击逻辑示例:
// 图片列表组件 export default function ImageGallery() { const loadImageData = async (imageId: string) => { const resp = await fetch(`/api/image-data/${imageId}`); const data = await resp.json(); // 后续业务逻辑写在这里,比如存到state里触发详情渲染 } return ( <div className="gallery"> {images.map(item => ( <img key={item.id} src={item.thumbnail} onClick={() => loadImageData(item.id)} alt={item.name} /> ))} </div> ) }
方案2:useFetcher 原生方案(更贴合Remix设计范式)
如果不想自己手写fetch处理加载状态、错误捕获,可以用Remix内置的useFetcher钩子,连单独的资源路由都不需要建:
- 在当前页面的
loader里加分支判断:如果检测到请求URL携带了特定参数(比如?intent=fetchImage&imgId=xxx),就调用query.server.ts的方法查对应数据返回,否则返回页面初始加载需要的常规数据。 - 组件内调用
useFetcher拿到fetcher实例,点击图片时调用fetcher.load()触发请求,直接从fetcher.data取返回数据、fetcher.state判断加载状态即可,不需要自己额外封装loading、错误处理逻辑。
踩坑提醒:绝对不要在客户端组件里直接import
query.server.ts的函数调用,这类带.server.ts后缀的文件会被Remix构建工具排除在客户端包之外,直接引入会报构建错误,所有涉及数据库操作的服务端逻辑,必须放在loader/action中通过HTTP请求触发。
内容的提问来源于stack exchange,提问作者canaryGrapher
相关产品推荐
相关产品推荐

