Next.js中如何将React状态传递给GraphQL变量实现数组数据过滤
核心问题说明
getStaticProps 是 Next.js 服务端侧执行的生命周期,仅在构建阶段、后台增量重生成时运行,完全无法访问客户端运行时的 React 状态,所以直接把组件内的 filter 传入 getStaticProps 的查询变量是不可能实现的,以下是3种可行实现方案:
方案1:全量预取 + 客户端过滤(最简单,适合数据量≤1000条的场景)
- 实现逻辑:
getStaticProps不传入name过滤条件,先拉取全量列表数据,组件内用状态filter直接对预取到的全量数据做过滤 - 代码示例:
// getStaticProps 去掉name变量,查询全量数据 export async function getStaticProps() { const { data, errors } = await client.query({ query: GET_LISTINGS, variables: { uri: '/listing/', name: '' // 传空或者直接去掉这个变量,查全量 } }) return { props: { allData: data || [], }, revalidate: 1 } } const Listings = ({ allData }) => { const [filter, setFilter] = useState({ city: '', area: '', type: '', }) // 新增过滤逻辑 const filteredData = allData?.listingCategoriesL?.nodes?.filter(category => { if (!filter.city) return true return category.name === filter.city }) || [] const handleSelectedFilter = e => { setFilter({ ...filter, [e.target.name]: e.target.value }) } // 渲染filteredData即可 return <div>{/* 渲染过滤后的列表 */}</div> } export default Listings
- 优缺点:实现成本最低,过滤无网络请求延迟,仅适合数据量不大的场景
方案2:客户端发起GraphQL查询(最灵活,适合数据量大、过滤条件多的场景)
- 实现逻辑:把GraphQL查询从
getStaticProps移到组件内部,使用Apollo Client的useQuery钩子,或者SWR/React Query等请求库,监听filter变化自动发起带过滤条件的查询 - 代码示例:
// 不需要在getStaticProps里查数据了,直接删掉getStaticProps,或者保留查首屏默认数据 const Listings = () => { const [filter, setFilter] = useState({ city: '', area: '', type: '', }) // 用useQuery触发查询,自动监听filter.city变化重新请求 const { data, loading } = useQuery(GET_LISTINGS, { variables: { uri: '/listing/', name: filter.city } }) const handleSelectedFilter = e => { setFilter({ ...filter, [e.target.name]: e.target.value }) } if (loading) return <div>加载中...</div> return <div>{/* 渲染data里的列表 */}</div> } export default Listings
- 优缺点:过滤逻辑灵活,支持任意复杂的多条件组合,过滤时会发起网络请求,需要处理加载状态
方案3:URL参数同步过滤状态 + 服务端查询(适合需要SEO、页面分享的场景)
- 实现逻辑:把用户选中的过滤条件同步到URL的查询参数中,比如选择
city=北京时跳转到/listing?city=北京,在getServerSideProps中读取URL参数的值,传入GraphQL查询变量返回过滤后的数据 - 代码示例:
export async function getServerSideProps(context) { // 从URL查询参数中获取city const { city = '' } = context.query const { data, errors } = await client.query({ query: GET_LISTINGS, variables: { uri: '/listing/', name: city } }) return { props: { data: data || [], defaultCity: city } } } const Listings = ({ data, defaultCity }) => { const [filter, setFilter] = useState({ city: defaultCity || '', area: '', type: '', }) const handleSelectedFilter = e => { const newCity = e.target.value setFilter({ ...filter, [e.target.name]: newCity }) // 同步到URL参数,触发服务端重新查询 window.history.pushState({}, '', `/listing?city=${encodeURIComponent(newCity)}`) } return <div>{/* 渲染data里的列表 */}</div> } export default Listings
- 优缺点:过滤后的页面可以直接分享,支持搜索引擎收录,每次过滤会触发页面级的服务端请求,延迟相对高一点
内容的提问来源于stack exchange,提问作者London Creative
相关产品推荐
相关产品推荐

