如何从组件中抽象出一个 graphQL 查询?

Posted

技术标签:

【中文标题】如何从组件中抽象出一个 graphQL 查询?【英文标题】:How to abstract a graphQL query out of the component? 【发布时间】:2020-01-20 03:58:18 【问题描述】:

我有一个 NextJS 项目,其中包含一个简单的 <PostList /> 组件,我使用 react-apollo 模块从 GraphQL 服务器检索一些测试数据:

import  gql, graphql  from "react-apollo";
import withData from "../../apollo/withData";

const GET_POSTS = gql`

  posts 
    _id
    title
  

`;

const PostList = (data: loading, posts) => 
    if(loading) 
        return (<div>Loading...</div>);
     else 
        return (
      <ul>
        posts.map(post => <li key=post._id>post.title</li>)
      </ul>
    );
    
;

export default withData(graphql(GET_POSTS)(PostList));

这很完美。但现在我想把那个查询定义拿出来,给它一个单独的.graphql(或.gql)文件。像这样的:

// apollo/get-posts-query.graphql


  posts 
    _id
    title
  

我的问题是,如何将这个文件导入到我的组件中,而无需将其转换为 javascript 代码?我的意思是,我不想在我的.graphql 文件中使用任何非graphql 代码(所以没有module.exports export default 等)。

这是我尝试过的所有内容:

使用 webpack

/* eslint-disable no-unused-vars */

import withCSS from '@zeit/next-css';
import withSass from '@zeit/next-sass';
import dotenv from 'dotenv';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import glob from 'glob';
import withPurgeCss from 'next-purgecss';
import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin';
import path from 'path';
import webpack from 'webpack';
import 'graphql-tag/loader';

const  parsed: localEnv  = dotenv.config();

module.exports = withCSS(withSass(withPurgeCss(
  distDir: '.build',
  purgeCssPaths: [
    'pages/**/*',
    'components/**/*',
  ],
  webpack: (config,  dev, isServer ) => 
    if (isServer) 
      return config;
    
    config.module.rules.push(
      test: /\.(graphql|gql)$/,
      exclude: /node_modules/,
      loader: 'graphql-tag/loader',
    );
    config.plugins.push(
      new webpack.DefinePlugin(
        'process.env': 
          BASE_URL: JSON.stringify(process.env.BASE_URL),
        ,
      ),
      new webpack.EnvironmentPlugin(localEnv),
      new webpack.optimize.LimitChunkCountPlugin(
        maxChunks: 1,
      ),
    );
    config.optimization.minimizer.push(
      new OptimizeCSSAssetsPlugin(),
    );
    return config;
  ,
  env: 
    REDIS_PORT: process.env.REDIS_PORT,
    REDIS_HOST: process.env.REDIS_HOST,
  ,
)));

此设置引发以下错误(甚至拒绝识别加载程序!):

./apollo/test.graphql 2:8 模块解析失败:意外令牌 (2:8) 您可能需要适当的加载程序来处理此文件类型,目前没有配置加载程序来处理此文件。见https://webpack.js.org/concepts#loaders | 帖子 | _ID |标题

使用 Babel

我添加了babel-plugin-import-graphql babel 插件(yarn add -D babel-plugin-import-graphql 到我的开发依赖项中)。然后更新我的.babelrc如下:


  "presets": [
    "next/babel"
  ],
  "plugins": [["styled-components",  "s-s-r": true ], "import-graphql"]


这会引发以下错误:

发生构建错误 Invariant Violation: Argument of posts _ID 标题 传递给解析器的 secondaryTitle 不是有效的 GraphQL DocumentNode。您可能需要使用“graphql-tag”或其他方法 将您的操作转换为文档 在不变(/home/ubuntu/proost/web-no-apollo/node_modules/invariant/invariant.js:40:15)

还有第三种选择吗?

【问题讨论】:

webpack:看起来加载器没有运行,尝试 console.logging 导出以查看加载器规则是什么。 babel 错误是因为 loader 没有运行 【参考方案1】:

您需要一个像 Webpack 这样的捆绑器,它可以让您定义如何加载 .graphql 文件。然后您只需导入 graphql 文件并像以前一样使用生成的查询字符串/对象。

一种可能是webpack-graphql-loader,但阿波罗recommends使用graphql-tag。

无论如何,你可以试试this approach specifically for Next.js。

【讨论】:

以上是关于如何从组件中抽象出一个 graphQL 查询?的主要内容,如果未能解决你的问题,请参考以下文章

如何从另一个组件重新获取 graphql 查询?

GraphQL入门指南

如何将数据从反应组件传递到 Apollo graphql 查询?

如何在组件外调用 GraphQL

如何在 Connect 组件下的 graphql 查询中使用 $filter 变量?

Graphql,react-apollo如何在加载组件状态时将变量传递给查询