使用 React 和 GraphQL 做一个todo list

英文:Igor Ribeiro Lima 译文:众成翻译/乐何 zcfy.cc/article/graphql-overview-build-a-to-do-list-api-with-a-react-front-end-mdash-sitepoint

设想你想要参考食谱烤一个蛋糕。你将需要一些原料,并且一些合适的量。如果你能拿一个盒子装好你烘焙所需要的各种原料 ,并且已经称量好匹配菜谱的份量,那肯定会让烘焙更简单。如果你把前端 UI设想成一块蛋糕的话,那这就是GraphQL所做的事。

在本教程中我们将写一个小的GraphQL server 来响应Todo List app的请求。你也可以 在众多app中来挑选,但是这些日子我开始使用React做项目,所以我将会选择React来做前端框架。不过,你也可以挑选你用得习惯的任何js框架。

GraphQL

GraphQL 允许我们定义 一个查询来提供一个通用的接口在客户端和服务端之间来请求和处理数据。它用一种查询语言来处理,允许客户端使用一种直观和灵活的语法和来按照客户端程序的设计和需求来构建和组装数据。

这使客户端从服务端 检索数据更加的高效。举个栗子,设想从一个 GraphQL的实例中, 客户端除了title和id 其它的字段一概不要,那么这个模型应该是长这样:

query Query {  todos {    id,    title  }}

结果数据(JSON)是:

Which produces the resulting data (in JSON):

{  "data": {    "todos": [      {        "id": 1446412739542,        "title": "Read emails"      },      {        "id": 1446412740883,        "title": "Buy orange"      },      {        "id": 1446412741215,        "title": "Fix garbage"      }    ]  }}

大概我们的展示demo中没有保存数据。这背后的原因是每次我们都启动服务,在内存中存储的Todo(s)数组变为空了。我们将在下面的内容中展示如何向数组中添加数据。

如你所见,返回的格式已经被替换成了客户端已经定义和描述过了的查询格式。就像文章“GraphQL 概述 – GraphQL 和 Node.js 入门 ”中规定的。

GraphQL的查询都像是没有属性的JSON对象,GraphQL 不是一种语言特性 这点被提到 很重要,它只是在客户端和服务端中间的一种规范。如果使用通用的语言,任何的客户端都能和任何服务端通信。

介绍 GraphQL.js

GraphQL.js 是一种基于js的GraphQL参考模型,它提供了两个重要的功能:

  1. 创建一种类型的语法模型(schema)。
  2. 应该该类型的语法(schema)的查询 。

需要创建一个匹配代码基层的GraphQL 类型语法(schema)。在接下来的代码中,我们定义一个简单的语法(schema)。它有一种类型和一个汇总的Todo(s)列表(每个列表元素有含有三个字段),额外的,它还提供了服务于该类型语法(schema)和查询结果。

var graphql = require ('graphql');
// Here is some dummy data to make this piece of code simpler.// It will be changeable after introducing mutation.var TODOs = [  {    "id": 1446412739542,    "title": "Read emails",    "completed": false  },  {    "id": 1446412740883,    "title": "Buy orange",    "completed": true  }];
var TodoType = new graphql.GraphQLObjectType({  name: 'todo',  fields: function () {    return {      id: {        type: graphql.GraphQLInt      },      title: {        type: graphql.GraphQLString      },      completed: {        type: graphql.GraphQLBoolean      }    }  }});
var queryType = new graphql.GraphQLObjectType({  name: 'Query',  fields: function () {    return {      todos: {        type: new graphql.GraphQLList(TodoType),        resolve: function () {          return TODOs;        }      }    }  }});
module.exports = new graphql.GraphQLSchema({  query: queryType});

让我们现在看一下给我们一个JSON数据结果的js文件的代码:

var graphql = require ('graphql').graphqlvar express = require('express')var graphQLHTTP = require('express-graphql')var Schema = require('./schema')var query = 'query { todos { id, title, completed } }'
graphql(Schema, query).then( function(result) {  console.log(JSON.stringify(result));  // Prints  // {  // "data":{  // "todos":[  // {  // "id":1446412739542,  // "title":"Read emails",  // "completed":false  // },  // {  // "id":1446412740883,  // "title":"Buy orange",  // "completed":true  // }  // ]  // }  // }});
var app = express()  .use('/', graphQLHTTP({ schema: Schema, pretty: true }))  .listen(8080, function (err) {    console.log('GraphQL Server is now running on localhost:8080');  });

下面的代码提供了跟上面同样 的执行结果,cURL在本例中并非是强制执行来得到 更长远的优势 的。它只是一种不用在浏览器中击中例子 来检索数据的方式 。请注意万一你是一个Windows 用户, 你可以使用Windows的命令提示符来执行cURL例子,此外, 这里你还可以找到好的资源来在你的系统里安装cURL.

$ curl -XPOST -H "Content-Type:application/graphql" -d 'query { todos { title } }' http://localhost:8080{  "data": {    "todos": [      {        "title": "Read emails"      },      {        "title": "Buy orange"      }    ]  }}

关于语法(schema)的一个重要的事情 ,自从它描述了用户可以使用的API,它就假定数据已经存储 了。数据存储和描述的方式是一种实现细节。

React

React 是由Facebook和Instagram来开发 的一种用来创建用户界面 JavaScript 库。很多人会认为React是MVC模型中的V, 官方文档中是这样规定的:

我们做出React是为了解决一个问题:创建大型应用时,加载数据超时。根源在于构建可重用的组件。实际上,本质就是构建组件库。

如果你需要一个React指南,你可以阅读下面的资料:

  • 视频: React入门
  • React JS库概述
  • 视频: 单向数据流概述

一个简单的React 组件

React 组件通过render()方法来获取输入数据并将返回结果渲染展示。这里是使用JSX(跟XML语法相似)的例子. JSX是一个非必须项。JSX是一种更像是XML的JavaScript 语法扩展,你可以使用React将简单的JSX语法转化。

输入数据可以通过this.props来向render()渲染的组件传值。下面是关于如何创建一个React 组件的简单的例子 并且在 CodePen中可用.

var Application = React.createClass({  render: function() {    return      { this.props.text }      { this.props.id }    ;  }});

和适当的这些预编译的代码,这些未编译过的JavaScript代码由JSX编译器生成。

"use strict";var Application = React.createClass({  displayName: "Application",  render: function render() {    return React.createElement(      "div",      null,      this.props.text,      this.props.id    );  }});

如果你想探究更多关于React 组件,可以花一分钟 看一下这个视频关于组件状态的介绍.

一次关于本例子的彩排

首先,我的们需要 一个服务端 (运行正常的)来接收我们从Todo List应用发出的GraphQL请求。这个服务端已经在上面写好了。

开启我们的服务,在命令行中执行:

$ git clone https://github.com/sitepoint-editors/todo-graphql-server.git$ cd todo-graphql-server$ npm install$ npm start

你必须已经安装Node v4.0.0以其更高的版本,因为 服务端的代码 使用了在老版本中并不支持的ES2015 特性 。

任何以/graphql结尾的POST请求 将会与我们的GraphQL语法(schema)发生执行冲突。测试一下是否正常运行,输入以下 代码 :

$ curl -XPOST -H "Content-Type:application/graphql" -d 'query { todos { title } }' http://localhost:8080{  "data": {    "todos": []  }}

还是没有数据保存。所以我们每次重启服务,在内存中的存储了todo(s) 数组数据都会被清空。当然 ,我们不单单想只读空数组,我们还需要添加和更新数据。这种接收异常类型的操作,在GraphQL中被 称作修改mutations),定义一个修改(mutations)跟定义一个查询一样,也会返回一个类型的的值。这个想法是无论什么变量发生了变化 ,就返回什么。

var MutationAdd = {  type: new GraphQLList(TodoType),  description: 'Add a Todo',  args: {    title: {      name: 'Todo title',      type: new GraphQLNonNull(GraphQLString)    }  },  resolve: (root, {title}) => {    TODOs.push({      id: (new Date()).getTime(),      title: title,      completed: false    });    return TODOs;  }};
var MutationType = new GraphQLObjectType({  name: 'Mutation',  fields: {    add: MutationAdd  }});
export var Schema = new GraphQLSchema({  query: QueryType,  mutation: MutationType});

上面的箭头符号 (=>) 参考定义函数的新语法, ES2015中最有趣的部分之一。

正如Clay Allsopp所写的这篇题为“Your First GraphQL Server” 文章中所写,

修改(mutation)与查询之间的一个有意义的区别是转换是串行的,但是查询没有这样的规定(实际上,GraphQL鼓励服务端为独立查询开发固有的并行模型)。GraphQL说明书提供 了这个关于修改(mutation)查询的一个集合例子必须按照下面的顺序在服务端执行:

{  first: changeTheNumber(newNumber: 1) {    theNumber  },  second: changeTheNumber(newNumber: 3) {    theNumber  },  third: changeTheNumber(newNumber: 2) {    theNumber  }}

因此,在请求结束, theNumber 字段值一定是2。在这个快速的修改(mutation)的介绍之后,我们可以最终在服务端添加一个todo 。

$ curl -XPOST -H "Content-Type:application/graphql" -d 'mutation { add (title: "Clean garage") { id, title } }' http://localhost:8080{  "data": {    "add": [      {        "id": 1446443172937,        "title": "Clean garage"      }    ]  }}

是不是相当的酷?我们除了这个添加(add)修改还有更多的修改(mutation):toggle, toggleAll, destroy, clearCompleted,和save。一个值得注意的事是我们在所有的修改中传递参数,所以有的字段都 可接收参数。追加参数是相当简单,并且它们都可以被resolve函数捕获。

今天的结尾,我们有两种类型的查询:

  • 一种是从服务端取数据(get);
  • 另一种是操作创建, 更新, 删除create, update, delete)数据。

服务正常运行后,我们已经准备好来用我们基于React的Todo List了。 React TodoMVC例子一个分支就像本文一开始提到 的那样,下载,并执行:

$ git clone -b react-graphql https://github.com/sitepoint-editors/todomvc.git$ cd todomvc$ npm install$ node server.js

浏览器中输入地址http://localhost:3000来运行应用。这个代码对比之前的版本有两个主要的变更。首先,服务端的TodoModel已经被修改了。

第二,我们本地创建了一个服务端代理来直接使用GraphQL 请求我们创建的服务。 更多的细节 ,查看下面的图片。

而且,你能 在这 找到一个demo。

总结

如你在本文所看到 的,GraphQL和GraphQL.js是Facebook在2015年最新发布的开源技术 ,它核心的想法是 UI知道组件需要渲染的数据的详细集合。

觉得本文对你有帮助?请分享给更多人。

原文发布于微信公众号 - 程序员宝库(chengxuyuanbaoku)

原文发表时间:2018-02-17

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏人工智能头条

机器学习新手必看:Jupyter Notebook入门指南

2044
来自专栏技术博文

关于微信二次分享,标题变链接的解决方法(二)----代码部分

声明: 本篇博文只是个人工作中的分享总结,仅代表个人观点,虽然解决了不少网友的问题,但同时也引来了一些网友的不满,所以特此声明,当您遇到本博文解决不了的问题,可...

3646
来自专栏魏艾斯博客www.vpsss.net

代码实现 WordPress 文章中英文数字间自动添加空格

2473
来自专栏封碎

Android的webview研究

最近做的项目大量用到了 webview ,用网页来布局。 Android 的 webview 是基于 webkit 内核,不过他的运行效果和 firefox 上...

1031
来自专栏小狼的世界

学习使用YUI3

对YUI一直很有好感,最近开始看了看YUI CSS GRID,发现这个理念非常好,非常有利于我们工作效率的提高,特别是熟悉了这套CSS之后,我们就不必每一个项目...

832
来自专栏小程序之家

如何在小程序中实现人脸识别功能

本文将介绍在小程序端,使用腾讯云云智AI应用服务来进行人脸识别检测分析,实现人脸识别等功能。

13.2K16
来自专栏林德熙的博客

win10 uwp x:Bind 无法获得资源

本文告诉大家,如果在 使用 x:Bind 转换器写在资源,而运行出现找不到资源的错误,如果解决。 在运行的时候,出现System.Runtime.Interop...

1263
来自专栏IT派

机器学习新手必看:Jupyter Notebook入门指南

【导读】Jupyter Notebook 是一个 Web 应用程序,便于创建和共享文学化程序文档,支持实时代码、数学方程、可视化和 Markdown,其用途包括...

3484
来自专栏偏前端工程师的驿站

Architecture Pattern: Publish-subscribe Pattern

1. Brief                               一直对Observer Pattern和Pub/Sub Pattern有所混淆,下...

19810
来自专栏云计算教程系列

如何在Python 3中安装pygame并创建用于开发游戏的模板

Pygame库是专门为了帮助您做出的游戏和其他多媒体应用Python编程语言的一个开放源代码模块。pygame 构建于高度可移植的SDL(Simple Dire...

6072

扫码关注云+社区

领取腾讯云代金券