同窗,GraphQL瞭解一下:實踐篇

上一篇:GraphQL瞭解一下:基礎篇
下一篇:GraphQL進階篇: 揮手Redux不是夢
在基礎篇主要講了GraphQL出現的意義與一些基礎語法。若是對GraphQL還不是很瞭解的同窗能夠點擊上方連接瞭解一下,再來跟進這一篇的實踐。本篇主要講述實現一個GraphQL Server與在React應用中引入GraphQL,代碼不難,推薦跟着手敲一遍。
下面文章的代碼均可以經過github下載:地址傳送,裏面包含兩個文件夾:graphqlServer(服務端)與graphqlApp(客戶端)。前端

實現一個GraphQL Server

技術棧準備

核心依賴(npm包):
express:Node服務端框架;
apollo-server-express:express graphql中間件,提供graphiqlExpress與graphqlExpress兩個方法;
graphql:graphql js實現基礎庫;
axios:ajax通訊,這裏用於和已有的Restful API通訊;
除了安裝以上的核心依賴,你還須要安裝babel相關的依賴,並配置babel編譯文件,具體可查看上面git下來的文件配置。react

搭建服務

怎麼引入包這裏再也不贅述,咱們先不帶入graphql,啓動一個express服務:webpack

const PORT = 8080;
    const app = express();  // 建立一個express服務;
    app.use('/graphql',  (req, res) => {
      res.send('Hello GraphQL!');
    });
    app.listen(PORT, () => console.log(`> Listening at port ${PORT}`));

啓動這個服務,並在瀏覽器輸入http://localhost:8080/graphql,能夠看到Hello GraphQL這段歡迎詞,到這裏咱們的後端服務已經搭建成功,接着咱們建立咱們的GraphQL服務,刪除監聽'/graphql'這個路由的代碼,添加一下一段代碼:ios

import schema from './schema';
    const PORT = 8080;
    const app = express();  // 建立一個express服務;
    app.use(cors()); //這裏添加cors,是由於咱們後面前端會單獨跑一個服務,因此涉及到先後端跨域
    app.use('/graphql', graphqlExpress({ schema }));
    app.use('/graphiql', graphiqlExpress({
        endpointURL: '/graphql'
    }));
    app.listen(PORT, () => console.log(`> Listening at port ${PORT}`));

至此,咱們就添加了GraphQL服務,graphql是用於接收url請求的,而graphiql會呈現一個graphql查詢界面,這個界面能夠用於查詢體驗,查看文檔定義,這是graphql官方比較推薦的一個技術,就像下面這樣:git

clipboard.png
上面咱們略過了schema,其實這個在上一篇就花了必定篇幅來說解,其定義了整個graphql服務所支持的接口定義,照樣貼上代碼:github

import {
      GraphQLObjectType,
      GraphQLSchema,
      GraphQLInt,
      GraphQLID,
      GraphQLString,
      GraphQLList,
      GraphQLNonNull,
    } from 'graphql/type';
    import { getUser, getUsers, getUserMixNick } from '../service/index';
    
    // 查詢某一個user的詳細資料模型
    const UserType = new GraphQLObjectType({
      name: 'User',
      fields: {
        id: { type: GraphQLInt },
        userName: { type: GraphQLString },
        userMixNick: { 
          type: GraphQLString,
          args: {
            id: {
                type: new GraphQLNonNull(GraphQLID)
            }
          },
          resolve: (root, args, context, info) => {
            const { id } = root;
            console.log(info)
            return getUserMixNick(id);
          }
         },
        military: { type: GraphQLString },
        age: { type: GraphQLInt },
        height: { type: GraphQLInt },
        education: { type: GraphQLString },
        enlistTime: { type: GraphQLString },
        enlistYear: { type: GraphQLInt },
      }
    });
    
    // 查詢全部的users
    const PaginationType = new GraphQLObjectType({
      name: 'Pagination',
      fields: {
        pageSize: { type: GraphQLInt },
        pageNum: { type: GraphQLInt },
        total: { type: GraphQLInt },
        data: {
          type: new GraphQLList(UserType)
        }
      }
    });
    // 定義schema
    const schema = new GraphQLSchema({
      query: new GraphQLObjectType({
        name: 'militaryQuery',
        fields: {
          user: {
            type: UserType,
            args: {
              id: {
                  type: new GraphQLNonNull(GraphQLID)
              }
            },
            resolve: (root, args, context, info) => {
              const { id } = args;
              return getUser(id);
            }
          },
          users: {
            type: PaginationType,
            args: {
              pageNum: { type: GraphQLInt },
              pageSize: { type: GraphQLInt }
            },
            resolve: (root, { filters, pageNum, pageSize }) => {
              return getUsers(filters, pageNum, pageSize);
            }
          }
        }
      })
    });
    
    export default schema;

這裏不想花太大的篇幅去講解,能夠git clone下來本身嘗試一下,至此咱們就成功的建立了一個GraphQL服務,能夠在graphiql界面查詢體會一下。web

在React應用中引入GraphQL

核心依賴(npm包):
react相關: 什麼react,webpack,react-router-dom這些;
react-apollo與apollo-boost: 用於在app端建立一個GraphQL服務鏈接實例;
graphql與graphql-tag: 用於在app端發出一個GraphQL請求;ajax

頁面結構

clipboard.png

頁面大體是這樣的一個結構,進入App的主頁時,會加載兄弟連中主要的戰士列表,點擊查看詳情,能夠看到這名展現的一些詳細信息,頁面結構代碼。express

<ApolloProvider client={client}>
    <Router>
      <div>
        <Route exact path="/" component={List} />
        <Switch>
          <Route exact path="/:id/detail" component={Detail} />
        </Switch>
      </div>
    </Router>
  </ApolloProvider>

這裏須要強調一下client代碼的實現:npm

const client = new ApolloClient({
      uri: 'http://localhost:8080/graphql',  // 服務端接口
      batchInterval: 10,
      opts: {
        credentials: 'cross-origin', // App端單獨跑了一個服務,因此涉及到跨域;
      },
    });

列表頁的實現

react-apollo在實現graphql結合react編程的方式上,借鑑了相似react-redux的connect高階組件的思想,react-apollo提供一個方法graphql用於生成一個容器,這個容器會從遠端拉去數據,而後做爲props傳遞給展現組件,直接看代碼的實現:

// 建立一個查詢  
      const USERS_QUERY = gql`
          query UserQuery($pageNum: Int,$pageSize:Int){
            users(pageNum:$pageNum,pageSize:$pageSize ) {
              pageNum
              pageSize
              total
              data {
                id
                userName
              }
            }
          }
    `;
    // 生成一個graphql容器,會執行USERS_QUERY這個查詢;
    const withQuery = graphql(USERS_QUERY, {
      options: () => ({
        variables: {
          pageNum: 3,
          pageSize: 8
        },
      }),
    });
    // 列表展現組件
    class List extends Component {
      constructor(props) {
        super(props);
        this.state = {};
      }
      render() {
        const { data: { loading, users } } = this.props;
        if (loading) {
          return <div className="loading">Loading...</div>;
        }
        const { data: lists, total } = users;
        return (
          <div>
            <p className="total">總共有<span>{total}</span>名軍士</p>
            <ul className="list">
              {
                lists.map(({ userName, id }, key) =>
                  <li key={key}>
                    <span>姓名:{userName}</span>
                    <Link to={`/${id}/detail`} >詳情</Link>
                  </li>
                )
              }
            </ul>
          </div>
        );
      }
    }
    // 將數據注入到展現組件中
    const Character = withCharacter(List);
    export default Character;

以上就是對列表展現組件的實現,思想仍是比較簡單,和咱們基於react + redux編程比較像。

詳情頁的實現

其實現思路和列表頁實際上是同樣的,只是涉及到動態傳參的問題,上查詢那一段代碼說一下:

const USER_QUERY = gql`
        query UserQuery($id: ID!){
          user(id:$id) {
            id,
            userName,
            age,
            military,
            height,
            education,
            enlistTime,
            enlistYear,
          }
        }
    `;
    const withQuery = graphql(USER_QUERY, {
      options: (props) => {
        const { match: { params } } = props; // 重點就是從props中獲取路由傳遞的參數
        return {
          variables: {
            id: params.id
          },
        };
      },
    });

withQuery這個高階組件一樣能夠從父組件中獲取props,而後經過其option方法動態的生成查詢參數,至於詳細頁展現組件的實現,能夠具體參考git上面的代碼。
到最後輸入url能夠看到以下的結果:

clipboard.png

思考

從寫一個demo的角度來說,在react中嵌入graphql好像比在在react中嵌入redux還簡單,但如何在咱們現有的框架中去嵌入graphql呢?好比Dva + graphql,好比react + redux + redux-thunk + graphql,在個人認知範圍裏,好像還須要時間去評估這一切值不值得,反正技術上確定是能夠實現的。引入graphql有多大價值,這也須要結合具體項目,具體業務,具體團隊來講。願你這兩篇文章讀完對GraphQL已經有了一個比較完整的認識,happy Ending!!!

相關文章
相關標籤/搜索