最近我们组在做项目的重构工作,重构的时候采用了全新的技术方案, 最大的变化就是技术选型的时候server端使用的是 GraphQL + apollo,用GraphQL代替了传统的restful风格的前后端数据处理
GATSBY是一款友好支持gql 的前端页面生成器
看一下对于Gatsby的基本解释:
Gatsby is a free and open source framework based on React that helps developers build blazing fast websites and apps
可以理解Gatsby 是一个静态页面生成工具,它允许使用React作为渲染引擎来搭建一个静态站点
目前比较知名的使用GatsbyJS 的站点就是 react官网
安装
通过Gatsby-cli 脚手架可以直接生产一个静态站点,
测试的时候发现,必须要求本地node版本号 12+
一个基本的框架生成之后是这个样子
GATSBY 的插件功能
GATSBY 拥有很多的插件
可以帮助我们实现非常丰富的功能,比如之后的demo,编译markdown文件,还有在别人的文章中看到可以在页面中添加离线地图应用等等
这里讲一个op中有使用的插件
gatsby-plugin-page-creator
gatsby中默认将 pages 作为路由映射文件,只要在pages中的文件都可以被映射为一个路由页面
那如果想要变更这个规则,就可以借助这个插件来处理
后面这个参数可以用来规避这种映射规则,如果你的组件不想作为路由展示,那么就可以在这里配置一下
支持请求
Gatsby 自然是支持我们常用的 RESTful API 风格
通过例子可以看到,也可以使用我们常用的这种数据请求,拿到数据做后续处理
const axios = require("axios")
const get = endpoint => axios.get(`https://pokeapi.co/api/v2${endpoint}`)
const getPokemonData = names => Promise.all(names.map(async name => {
const {data: pokemon} = await get(`/pokemon/${name}`)
return {
...pokemon
}
}))
但是Gatsby 更推荐我们使用 gql 去处理数据,甚至是静态资源的读取,比如我们看一下关于站点内静态图片的展示 【 gatsby-blog 】
去展示一个图片都是通过gql访问的方式
const Image = () => {
const data = useStaticQuery(graphql`
query {
placeholderImage: file(relativePath: { eq: "gatsby-astronaut.png" }) {
childImageSharp {
fluid(maxWidth: 300) {
...GatsbyImageSharpFluid
}
}
}
}
`)
return
}
这种图片的处理我们也可以按照以往的require方式去实现
src={fixUrl(item.avatar)}
但是gatsby是建议我们去遵循同一套开发风格
这种理念可以说是一种开发规范或者说约定吧,希望可以统一开发者的风格
那这种方案对于团队开发来说比较好,统一的风格有利于之后项目的管理与开发,如果是个人站定的搭建就怎么简单怎么实现了
页面生成
Gatsby支持2种页面生成的方式
- 1 Gatsby内置自动将src / pages中的React组件生成路由的页面,这个也是我们现在后台重构时候采用的方式
- 2 gatsby-node.js 中 通过 createPage.函数生成
通过这里例子可以看到我们可以拿到数据后动态生成页面
createPage({
path: `/pokemon`,
component: require.resolve("./src/templates/pokemon.js"),
context: {
allPokemon
}
})
构建demo
然后我们来写一个demo来感受一下 gatsby 的实际开发
demo的目标可以看做是博客内容展示
Demo :文章列表页面 + 详情页面
基本逻辑:读取markdown 数据,展示页面
过程非常简单:
1 首先我们中配置两个插件
gatsby-source-filesystem
gatsby-transformer-remark
Filesystem 是读取文件资源
remark帮助解析markdown数据
2 template中创建模块文件
3 然后我们在gatsby-node.js 中配置动态页面的渲染
// 生成一个markdown 目录文件
const markdownData = result.data.allMarkdownRemark.edges
const articles = markdownData.map(({ node }) => node.frontmatter)
// 首页列表渲染 - 备注由于 GATSBY 首先读取配置 在走默认设置 所以page文件夹需要调整 不然就会读取pages下的文件作为首页了
createPage({
path: '/',
component: path.resolve(`src/templates/index.js`),
context: {
articles
}
})
// markdown 遍历生成单独的文章页面
result
.data
.allMarkdownRemark
.edges
.forEach(({node}) => {
createPage({
path: node.frontmatter.path,
component: path.resolve(`src/templates/post.js`)
})
})
createPage 函数 中path 是指定到页面展示的路由,component 是你使用的模板引擎,context 是需要传递给模板需要渲染的数据
列表页面所需的,头像、时间等参数都是在markdown文件中写入的
---
title: 画个龙
date: 2019-08-10
path: /rainbow
author: mk
cover: https://www.lxybaike.com/uploads/201907/1562575542zU2C2i60.jpg
---
我是mk文件 我是mk文件 我是mk文件
以上就完成了一个简单的列表展示功能
项目实战
数据请求
按照之前的restful风格。接口分为get与post类型,对应gql中可理解为
get -> Query
post -》 Mutation
const { loading, error, data } = useQuery(GET_TODOS)
const [updateTodo] = useMutation(UPDATE_TODO)
按钮操作后更新页面数据可以通过4种方式实现
1 接口中返回变更的结果,根据id会查询到缓存,会自动更识符,用来作为重新获取对象或者缓存的key —- 所以返回的数据列表中不可以有重复id出现
说到这个想起之前,由于mysql表中使用id + order 作为了联合主键,请求返回的数据有相同的id,导致写入缓存数据出错
2 在 update 中 主动重写 cache ( 这个是目前比较常用的一个, readquery && writequery ) 【 mutation 】
3 使用 refetch 直接重新发起一次请求 【 query 】
4 文档中还有一种, fetchmore 在举例分页操作的时候可以使用,不过尝试了下这种方法,这个要配合 updatequery 函数操作
,不如使用 setxxx 去变更 variables 【 query 】