在Remix React中基于GraphQL实现Shopify Storefront搜索组件
在Remix中实现搜索功能的两种方案
对于你的问题,查询可以直接在客户端组件中处理,也可以通过Remix的服务端路由来实现(更推荐后者,尤其是API需要密钥等敏感信息时),下面是具体实现方式:
方案一:客户端直接发起GraphQL请求(适合公开API)
如果你的GraphQL API无需敏感验证,可以直接在handleSearch中用fetch发送请求:
async function handleSearch() { if (!searchTerm.trim()) return; try { const response = await fetch('你的GraphQL API地址', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ query: SEARCH_PRODUCTS_QUERY, variables: { query: searchTerm } }) }); const data = await response.json(); if (data.data?.products?.edges) { setSearchResults(data.data.products.edges); } } catch (error) { console.error('搜索失败:', error); } }
方案二:用Remix服务端Action处理(推荐,更安全)
如果API需要密钥或敏感信息,必须通过服务端路由转发请求,避免客户端暴露敏感数据:
1. 创建服务端路由处理搜索请求
在app/routes下新建api.search.tsx(或api/search.ts):
import { json } from "@remix-run/node"; export async function action({ request }: { request: Request }) { const formData = await request.formData(); const searchTerm = formData.get('query') as string; if (!searchTerm.trim()) { return json({ products: [] }, { status: 400 }); } // 服务端调用GraphQL API,可安全使用密钥 const response = await fetch('你的GraphQL API地址', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer 你的API密钥' // 按需添加 }, body: JSON.stringify({ query: ` query SearchProducts($query: String!) { products(query: $query, first: 10) { edges { node { id title handle description } } } } `, variables: { query: searchTerm } }) }); const data = await response.json(); return json({ products: data.data?.products?.edges || [] }); }
2. 修改SearchForm组件调用服务端路由
import { useState } from "react"; function SearchForm() { const [searchTerm, setSearchTerm] = useState(''); const [searchResults, setSearchResults] = useState([]); const [isLoading, setIsLoading] = useState(false); async function handleSearch() { if (!searchTerm.trim()) return; setIsLoading(true); try { const response = await fetch('/api/search', { method: 'POST', body: new FormData().append('query', searchTerm) }); const data = await response.json(); setSearchResults(data.products); } catch (error) { console.error('搜索失败:', error); } finally { setIsLoading(false); } } return ( <div> <input type="text" placeholder="search" value={searchTerm} onChange={(event) => setSearchTerm(event.target.value)} /> <button type="button" onClick={handleSearch} disabled={isLoading}> {isLoading ? '搜索中...' : '搜索'} </button> <ul> {searchResults.map((product) => ( <li key={product.node.id}>{product.node.title}</li> ))} </ul> </div> ); }
总结
- 公开API可直接在客户端处理请求;
- 涉及敏感信息的API必须通过Remix服务端路由转发,保障安全;
- Remix推荐用服务端处理数据请求,便于统一控制缓存、错误逻辑和权限验证。
内容的提问来源于stack exchange,提问作者avocado
相关产品推荐
相关产品推荐

