GraphQL、useQuery、useMutation的基础使用
前言
上周五的毕业典礼举行完了,工作也落实了有一段时间了,总结一下最近学到的技术以及一些存在的问题总是好的。这段时间实习工作的技术栈是react+ts+gql,也是我第一次接触gql,用了感觉真香,在使用过程中主要是配合react的函数式组件进行使用,作用简而言之就是查询然后发请求返回数据,替代了axios,fetch和原生的ajax请求,也不能叫替代吧就是大体作用相差不大,比起上面的方法,它不用再去书写请求头,方法类型啊等等。
GraphQL(gql)
在最开始使用的时候看了不是博文,这篇GraphQL入门到实践说实话还不错,写的概念上还是很规范也通俗易懂,基本大体浏览一下就知道gql是什么大体使用就清楚了,但是对接我自己的项目肯定还是有不同的地方。
接口文档以前自己做项目看的都是swigger,来这边之后因为要配合gql的使用,接口文档就是这样的:
上面的QUERIES,就是类似于我们的GET请求,下面的MUTATIONS就是类似于POST请求,在具体的gql使用上代码如下:
import { gql } from "@apollo/client"
class Api {
// 不需要传参的查询,查后端adminInfo接口返回id和listTask接口默认传skip为0,返回status
adminInfo = gql`
{
adminInfo {
id
}
listTask(
skip:0
){
status
}
}
`
// 查询带有默认值,可进行传参或直接查询
groupList = gql`
query(
$key: String = ""
$limit: Int = 10
) {
list: groupList(
key:$key,
limit:$limit,
) {
founder{
lastLogin{
str
}
id
}
}
groupCount(
key:$key
)
adminList(
limit:$limit
){
id
}
baseData {
followTags
}
}
`
//类似于POST !表明为必传项 EnumType是枚举类型
modifyGroupStatus = gql`
mutation(
$note: String!
$groupId: String!
$status: GroupCrmStatusEnumType!
$tag: String
){
modifyGroupStatus(
note:$note
groupId:$groupId
status:$status
tag:$tag
){
id
}
}
`
//[xxxxxx]传的是一个数组,每个数组是一个对象(具体看后台约定为什么)
saveFaqType = gql`
mutation(
$args:[saveFaqTypeInput]
){
saveFaqType(args:$args){
id
questions{
question
}
}
}
`
}
const api = new Api()
export default api
useQuery
useQuery就是配合gql进行查询的操作,但是在一个函数式组件中只能用一个useQuery,所以想要获取多个接口的数据要么拆分为多个函数式组件,要么写在gql中拼接返回数据。
import { useQuery } from "@apollo/client";
import api from "src/services/api";
export default function Tracked() {
// data 查询的结果
// refetch用于重新进行useQuery的请求
// loading 加载中 返回的error信息
// fetchPolicy: "no-cache" 不缓存查询的结果
// 不传值的查询 const { loading, error, data } = useQuery(api.adminInfo)
const { data, refetch, loading,error } = useQuery(api.groupList, { variables: { limit: 10, key: '我是关键字' },fetchPolicy: "no-cache" })
//一般data要配合useState保存数据
//分页点击
const pageChange = (pageSize: number) => {
refetch({ limit: pageSize, key: key })
}
}
useLazyQuery
useLazyQuery 也是查询,它和useQuery的不同点在于useQuery是一进入某个组件就会自动去查询数据,且在一个函数组件中通常useQuery只有一个,而useLazyQuery则是事件触发时的查询,如按钮点击时。
import { useLazyQuery } from "@apollo/client";
const [exportOrders, { data: dataExport, error: errExport }] = useLazyQuery(api.purch.exportOrders, {
onCompleted: someData => {
// console.log('someData', someData)
/* do your staff */
}
});
//也可以去监听里面数据的变化
useEffect(() => {
if (dataExport) {
// message.success('导出成功')
console.log('dataImport', dataExport);
/* do your staff */
}
}, [dataExport])
//函数调用传参
const exportOut = (id: string) => {
exportOrders({ variables: { fileId: id } })
}
return (
<Button className='out-btn' shape='round' onClick={() => { exportOut(item.id) }}>导出</Button>
)
useLazyQuery踩坑记录
当要去设置loading状态,如在函数组件中,查询出来的数据和上次相同则不会触发useEffect <连续点击进行查询的调用>
const [loading, setLoading] = useState(false) //点击查询按钮的loading
const [getList, getListRes] = useLazyQuery(api.list, { fetchPolicy: 'no-cache' });
const [resErr, setResErr] = useState<any>(null)
useEffect(() => {
if (getListRes?.data) {
let data = getListRes.data
console.log('-res--', data);
setList(data.list)
}
}, [getListRes?.data])
// 获取列表信息
const getGoodsClearList = async (v: any) => {
if (getListRes.called) {
//不是首次调用了 自定义loading
setLoading(true)
try {
await getListRes.refetch(v)
}
catch (ex) {
setResErr(ex)
}
setLoading(false)
} else {
//首次调用lazyQuery --> getListRes.loading生效
getList({ variables: v })
}
}
const okLoading = getListRes.loading || loading
// 异常处理
{
getListRes?.error || resErr ?
<div className='err-text'>
<ErrorView error={resErr || getListRes.error} />
</div>
:
<div>正常的显示数据</div>
}
useMutation
useMutation是可以在一个函数组件中多次使用的
import { useMutation } from "@apollo/client";
//封装的Mutation方法:
export async function invokeMutationFunction<TData = any, TVariables = OperationVariables>(
mfunc: MutationFunction<TData, TVariables>,
options?: MutationFunctionOptions<TData, TVariables>) {
// console.log('invokeMutationFunction',options);
try {
return await mfunc.call(null, options)
} catch (error) {
showErrorMessage(error)
return undefined
}
}
//定义枚举类型
export enum GroupCrmStatusEnumType {
INVALID = 'INVALID',
// 无效客户
DISTRIBUTION = 'DISTRIBUTION',
// 待分配
FOLLOW = 'FOLLOW',
// 待跟进
EFFECTIVE = 'EFFECTIVE'
// 有效客户
}
export function GroupModalEffective(props:any) {
let modifyState = {
note: '',
groupId: "",
status: '',
tag: ''
}
const [changeState] = useMutation<any, any>(api.modifyGroupStatus)
const [saveFaqType] = useMutation<any, any>(api.saveFaqType)
const handleOk = async () => {
modifyState.groupId = tempArr.groupId
modifyState.status = GroupCrmStatusEnumType.FOLLOW
const res = await invokeMutationFunction(changeState, {
variables: modifyState
})
let args: any = []
fenleiArr.forEach((item, index) => {
if (item.name != '') {
//具体看后台约定数组里面是什么对象就进行添加
args.push({
order: index,
name: item.name,
id: item.id == undefined ? '' : item.id
})
}
})
const res = await invokeMutationFunction(saveFaqType, {
variables: { args }
})
}
//res就是后台返回的数据
}
include、skip的使用
include和skip在GraphQL中是相反的作用,include判断结果为真执行,反之不执行,在设置请求时候可自定义是否进行对应数据的查询,加快响应速度。
export default `query(
$supplyId: String = ""
$supplyInfoLoad: Boolean = true
){
founder{
supplyInfo(id:$supplyId)
@include(if: $supplyInfoLoad){
logo
nickname
}
}
}`