一、案例背景
七镜在基于react编写页面时,发现一段每个页面都重复的graphql相关代码,代码如下:
// 标记1 const [dataNews, setDataNews] = useState<TGqlDimensionNews>({ code: 0, content: [], count: 0, msg: {fail: "", success: ""} }) // 标记2 const [condNews, setCondNews] = useState<TCondType>({ page_after: 0, page_size: 10, order_by: "created_at", sort_by: "desc", detail: {}, keyword: { }, table_name: "dimension_news", }) // 标记3 //useGraphql const [getDimensionNews, {data: dataDimensionNews, error}] = useLazyQuery(QUERY_DIMENSION_NEWS) // 标记4 // useEffect: useEffect(() => { getDimensionNews({ variables: { from_id: auth.data.base.id, from_nickname: auth.data.account, content: JSON.stringify(condNews) } }) .then(resp => { let tmpData = {...resp.data.dimensionNews} as TGqlDimensionNews // console.log("result:", tmpData.content[0].base_dimension.content) if (tmpData.code === 200) { setDataNews(tmpData) } }) .catch(e => { console.log(e) }) }, [condNews])
- 标记1:定义服务端数据接收过来的结构体
- 标记2:定义服务端数据获取的过滤条件
- 标记3:定义graphql数据获取的函数入口
- 标记4:通过graphql数据获取函数接收服务端数据,并存入保存页面数据的地方(dataNews)
我们知道,写代码的时候,面对第一个新需求,快速实现一段代码;面对第二个差不多的需求,针对刚刚那段代码,复制粘贴并做一些小小的修改;面对第三个差不多的需求,应当重构前面的代码。
二、优化方案
首先,技术实现肯定是基于 react hooks。详细代码如下:
import React, {useState, useEffect, useContext} from "react"; import {DocumentNode, useLazyQuery} from "@apollo/react-hooks"; import { TCondType, TResponseCommon } from "../../register-center/graphql/graphql-types/graphql-types"; import {ContextAuth} from "../../register-center/context/auth/context-auth"; export interface useGraphqlGetProps { cond: TCondType, // 接口参数 gql_schema_query: DocumentNode, // Graphql schema gql_data_query_name: string, // 查询的表名 setData: React.Dispatch<React.SetStateAction<TResponseCommon>> // 设置查询结果 } function useGraphqlQuery(props: useGraphqlGetProps): [TCondType, React.Dispatch<React.SetStateAction<TCondType>>] { const [auth, setAuth] = useContext(ContextAuth) // 接口参数中的用户名和用户昵称的来源 const [cond, setCond] = useState<TCondType>(props.cond) //useGraphql const [getData, {error}] = useLazyQuery(props.gql_schema_query) // useEffect useEffect(() => { if (!cond.table_name) { console.error("please replace cond.table_name") return } getData({ variables: { from_id: auth.data.base.id, from_nickname: auth.data.account, content: JSON.stringify(cond) } }) .then(resp => { let tmpData = {...resp.data[props.gql_data_query_name]} // console.log("result:", tmpData.content[0].base_dimension.content) if (tmpData.code === 200) { props.setData(tmpData) } }) .catch(e => { console.error(e) }) }, [cond]) return [cond, setCond] } export default useGraphqlQuery
实现思路:
- 该hook的初始化依赖于传入的【接口参数】、【graphql schema】、【查询的表名】、【设置查询结果的函数】
- 该hook中的实现逻辑与之前代码一致。
- 替换之前的代码中与传入参数一致的地方。
三、优化结果
优化后计入数据的代码:
const [data, setData] = useState<TGqlDimensionApplicationCase>(initResponseCommon) const [cond, setCond] = useGraphqlQuery({ cond: { ...initCond, table_name: "dimension_application_case", }, gql_schema_query: QUERY_DIMENSION_APPLICATION_CASE, gql_data_query_name: "dimensionApplicationCase", setData: setData })
从优化前后的代码行数,可以看到代码量已经大大减少了,封装完毕。