ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

详解企业级使用Graphql开发项目

2021-06-28 18:01:43  阅读:203  来源: 互联网

标签:const 企业级 react 详解 graphql client import Graphql apollo


一、基本环境搭建

  • 1、创建一个react项目

    npx create-react-app react-graphql --template typescript
    
  • 2、根据文档在react中配置Graphql的环境,链接地址

    • 安装依赖包

      npm install @apollo/client graphql
      
    • 在index.ts中配置连接graphql的后端地址

      import { ApolloClient, InMemoryCache } from '@apollo/client';
      
      const client = new ApolloClient({
        uri: 'http://localhost:7001/graphql',
        cache: new InMemoryCache()
      });
      
    • 在index.ts文件中将apollo与react相连接起来

      import { ApolloProvider } from '@apollo/client/react';
      
      import React from 'react';
      import ReactDOM from 'react-dom';
      import App from './App';
      import { ApolloClient, InMemoryCache } from '@apollo/client';
      import { ApolloProvider } from '@apollo/client/react';
      
      const client = new ApolloClient({
        uri: 'http://localhost:7001/graphql',
        // 在这里配置请求头了
        headers: {
          token: storage.getItem(authToken),
        },
        cache: new InMemoryCache()
      });
      
      ReactDOM.render(
        <React.StrictMode>
          <ApolloProvider client={client}>
            <App />
          </ApolloProvider>
        </React.StrictMode>,
        document.getElementById('root')
      );
      
    • 运行项目看是否正常

  • 3、测试是否可以查询数据出来

    import React from 'react';
    import { useQuery, gql } from '@apollo/client';
    
    const AccountListGql = gql`
      query AccountList { # 定义查询方法(浏览器上显示的)
        accountList { # 定义与后端对接的方法名
          id
          username
          password
        }
      }
    `;
    
    export const Page1: React.FC = () => {
      const { loading, error, data } = useQuery(AccountListGql);
      console.log(loading);
      console.log(error);
      console.log(data);
      return <div>测试查询数据</div>
    }
    

二、查询数据

  • 1、简单的查询,上面使用useQuery就可以实现

  • 2、需要传递参数的查询

    import React from 'react';
    import { gql, useQuery } from '@apollo/client';
    
    const AccountGql = gql`
      query Account($id: ID!) {
        account(id: $id) {
          id
          username
          password
        }
      }
    `;
    export const Page2: React.FC = () => {
      const {  data } = useQuery(AccountGql, {
        variables: {
          id: 1
        }
      });
      console.log(data, '查询结果');
      return <div>根据条件来查询</div>
    }
    
  • 3、点击按钮才触发请求

    import React from 'react'
    import { gql, useLazyQuery } from '@apollo/client';
    
    const AccountListGql = gql`
      query AccountList { # 定义查询方法(浏览器上显示的)
        accountList { # 定义与后端对接的方法名
          id
          username
          password
        }
      }
    `;
    
    export const Page3: React.FC = () => {
      const [getAccount, { loading, data }] = useLazyQuery(AccountListGql);
      if (loading) return null;
      console.log(data, '请求回来的数据');
      return (
        <div>
          点击按钮请求数据
          <button onClick={() => getAccount()}>点击按钮</button>
        </div>
      )
    }
    
  • 4、点击按钮触发,需要传递参数进去

    const AccountGql = gql`
      query Account($id: ID!) {
        account(id: $id) {
          id
          username
          password
        }
      }
    `;
    
    export const Page3: React.FC = () => {
      const [getAccount, { loading: loading2, data: account }] = useLazyQuery(AccountGql);
      console.log(account, '根据条件返回的数据');
      return (
        <div>
          点击按钮请求数据
          <button onClick={() => getAccount({variables: {id:2}})}>传递参数按钮</button>
        </div>
      )
    }
    
  • 5、关于更多的使用请参考文档文档地址

三、对数据的增删改操作

  • 1、文档地址

  • 2、添加数据的操作

    import React from 'react';
    import {gql, useMutation} from '@apollo/client';
    
    const AddAccountGql = gql`
      mutation AddAccount($username: String!, $password: String!) {
        createAccount(username: $username, password: $password) {
          code
          message
        }
      }
    `;
    
    export const Page4: React.FC = () => {
      const [addTodo, { data }] = useMutation(AddAccountGql);
      console.log(data, '创建结果');
      const addAccountHandle = () => {
        addTodo({
          variables: {
            username: '王五',
            password: '123456',
          }
        })
      };
      return (
        <div>
          <h3>添加数据</h3>
          <button onClick={addAccountHandle}>添加数据</button>
        </div>
      )
    }
    

四、文件上传

上面的配置仅仅的对于简单的业务可以满足,如果你要对文件的上传操作上面的配置是不行的,下面介绍在graphql中上传文件的方式

  • 1、安装依赖包

    npm install apollo-upload-client@14.1
    npm install @types/apollo-upload-client -D
    
  • 2、修改graphql的配置项,必须要这样配置

    import { createUploadLink } from 'apollo-upload-client';
    ...
    const client = new ApolloClient({
      // uri: 'http://localhost:7001/graphql',
      link: {
        uri: 'http://localhost:7000/graphql',
        // 在这里配置请求头了
        headers: {
          token: storage.getItem(authToken),
        },
      },
      cache: new InMemoryCache()
    });
    
  • 3、在react中使用文件上传,这里使用自定义按钮来上传,因为html中自带的上传文件样式太丑了

    import { useMutation, gql, useQuery } from '@apollo/client';
    
    // 上传文件的gql
    const fileUploadGql = gql`
      mutation FileUpload($file: Upload!) {
        fileUpload(file: $file)
      }
    `;
    // 省去100行代码
    ...
    const [uploadFileApi, { data: uploadResult, error: uploadError }] = useMutation(fileUploadGql);
    ...
    // 省去100行代码
    
    const uploadHandler = () => {
      const fileNode: HTMLElement = document.getElementById('file') as HTMLElement;
      fileNode.click();
      fileNode.addEventListener<'change'>(
        'change',
        function ({
          target: {
            validity,
            files: [file],
          },
        }: // eslint-disable-next-line
                   any) {
          setIsShowFile(false);
          validity.valid && uploadFileApi({ variables: { file } });
          setTimeout(() => {
            setIsShowFile(true);
          });
        }
      );
    };
    
    // 省去100行代码
    {isShowFile && <input type="file" id="file" style={{ display: 'none' }} />}
    {imgUrl && (
      <img src={imgUrl} alt="" style={{ width: 100, height: 100, marginBottom: 10 }} />
    )}
    <div>
      <Button type="primary" onClick={uploadHandler}>上传封面图</Button>
    </div>
    

五、关于apollo错误处理

一般我们使用restfull api的时候会对axios二次封装,在里面统一处理错误,比如token失效的时候你要重定向到登录页面,上面介绍的方法中我们仅仅是使用apollo打通了前后接口,数据能增删改查,也能上传文件了,如果你的业务中没有登录的限制这里也可以不用关心了。但是作为有追求的码农,总要彻底的掌握一门技术,下面介绍如何对apollo二次简单封装,来处理错误

  • 1、在utils/initApollo.ts中对apollo简单的封装

    import {
      ApolloClient,
      ApolloLink,
      from as fromLinks,
      InMemoryCache,
      NormalizedCacheObject,
      QueryOptions,
      WatchQueryOptions,
    } from '@apollo/client';
    import { one rror } from '@apollo/client/link/error';
    import { createUploadLink } from 'apollo-upload-client';
    import { authToken } from 'src/config';
    import { storage } from './storage';
    
    let apolloClient: ApolloClient<NormalizedCacheObject> | null = null;
    
    const defaultOptions = {
      watchQuery: {
        fetchPolicy: 'no-cache',
        errorPolicy: 'ignore',
      } as WatchQueryOptions,
      query: {
        fetchPolicy: 'no-cache',
        errorPolicy: 'all',
      } as QueryOptions,
    };
    
    function create(): ApolloClient<NormalizedCacheObject> {
      const httpLink = createUploadLink({
        uri: 'http://localhost:7000/graphql',
        headers: {
          token: storage.getItem(authToken),
        },
      });
      const authMiddleware = new ApolloLink((operation, forward) => {
        const token = storage.getItem(authToken);
        if (token) {
          operation.setContext({
            headers: {
              token,
            },
          });
        }
        return forward(operation);
      });
      // 处理错误的时候
      const errorLink = one rror(({ graphQLErrors, networkError }) => {
        console.log(graphQLErrors, '错误');
        if (graphQLErrors) {
          graphQLErrors.map(({ message, locations, path }) => {
            // 根据错误处理业务,省去100行代码
            console.log(`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`);
            return false;
          });
        }
        if (networkError) {
          console.log(`[Network error]: ${networkError}`);
        }
      });
      return new ApolloClient({
        // errorLink 应在 httpLink 前
        link: fromLinks([errorLink, authMiddleware, httpLink]),
        cache: new InMemoryCache(),
        defaultOptions,
        connectToDevTools: true,
      });
    }
    
    export const initApollo = (): ApolloClient<NormalizedCacheObject> => {
      if (!apolloClient) {
        apolloClient = create();
      }
      return apolloClient;
    };
    
  • 2、在react的入口文件中使用

    import { initApollo } from './utils';
    
    const client = new ApolloClient(initApollo());
    
    ReactDOM.render(
      <ApolloProvider client={client}>
      	<Router />
      </ApolloProvider>,
      document.getElementById('root')
    );
    

六、使用后端的schema自动生成hooks

  • 1、参考文档

  • 2、安装依赖包

    npm install --save graphql
    npm install --save-dev @graphql-codegen/cli
    
  • 3、初始化,直接选择默认和Y就可以

    npx graphql-codegen init
    

    在这里插入图片描述

  • 4、默认生成的codegen.yml文件修改如下

    overwrite: true
    schema: "http://localhost:7000/graphql" # 根据自己后端服务器地址来写,
    # schema: "./schema.graphql" # 将后端的schema拷贝到前端项目中
    documents: "src/**/*.graphql" # 表示会去查找graphql结尾的文件
    generates:
      src/generated/graphql.ts:
        plugins:
          - "typescript"
          - "typescript-operations"
          - "typescript-react-apollo"
    
  • 5、我们在src文件夹下创建一个graphql的文件夹,创建两个login.graphql和register.graphql文件

    # login.graphql文件内容
    query Login($username: String!, $password: String!) {
      # 定义查询方法(浏览器上显示的)
      login(data: { username: $username, password: $password }) {
        id
        username
        token
      }
    }
    
    # register.graphql文件内容
    mutation registerUser($username: String!, $password: String!, $confirmPassword: String!) {
      register(data: { username: $username, password: $password, confirmPassword: $confirmPassword })
    }
    
  • 6、运行安装依赖包

    使用命令npx graphql-codegen init初始化的时候,并不会帮我们安装依赖包的,只是会添加依赖包到package.json中

  • 7、运行命令生成对应的hooks,注意这个要看自己根据第三小点生成的命令来运行,或者自己配置的命令

    npm run codegen
    
  • 8、在生成的src/generated/graphql.ts文件中最底部可以查看到生成了登录和注册的hooks,因为我们只写了这两个接口的graphql文件

  • 9、在App.tsx组件中调用

    import React, { useEffect } from 'react';
    import { useLoginLazyQuery, useRegisterUserMutation } from './generated/graphql';
    
    function App(): React.ReactElement {
      const [loginApi, { data: loginResult }] = useLoginLazyQuery();
      const [registerApi] = useRegisterUserMutation();
      const loginHandler = () => {
        loginApi({ variables: { username: 'admin', password: '123456' } });
      };
      const registerHandler = async () => {
        const result = await registerApi({ variables: { username: 'test1', password: '123456', confirmPassword: '123456' } });
        console.log(result, '注册结果');
      };
      useEffect(() => {
        if (loginResult) {
          console.log('登录信息', loginResult);
        }
      }, [loginResult]);
      return (
        <div className='App'>
          <button onClick={loginHandler}>登录</button>
          <button onClick={registerHandler}>注册</button>
        </div>
      );
    }
    
    export default App;

标签:const,企业级,react,详解,graphql,client,import,Graphql,apollo
来源: https://blog.51cto.com/u_3409716/2952051

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有