怎么样把Apollo GraphQL给整合进来?官方能不能给个思路
或许应该有个@taro-apollo...
https://www.apollographql.com/docs/react/essentials/get-started.html
@janpo Apollo GraphQL 这个库我们还没使用过,暂时给不了思路,你看看能不能为 Taro 增加这个支持呢,非常欢迎~
@janpo 拿走别客气
仿照react-apollo 1.x版做的
client是个apollo client 你可以放个静态变量或者import
```
function optionsEqual(op1, op2) {
if (_.isEmpty(op1) && _.isEmpty(op2)) {
return true;
}
if (_.isEmpty(op1) || _.isEmpty(op2)) {
return false;
}
return op1.query === op2.query && _.isEqual(op1.variables, op2.variables);
}
export function withQuery(config = {}) {
const {
query: configQuery,
variables: configVariables,
} = config;
const evalQuery = (props, state) => {
const query = _.isFunction(configQuery) ? configQuery(props, state) : configQuery;
if (!query) {
throw new Error("null query!!");
}
return query;
};
const evalVariables = (props, state) => {
return _.isFunction(configVariables) ? configVariables(props, state) : configVariables;
};
const shouldSkip = (props, state) => {
const query = evalQuery(props, state);
if (!query) {
return true;
}
const queryNeedsVariable = !!_.get(query, "definitions.0.variableDefinitions.0");
return queryNeedsVariable && !evalVariables(props, state);
};
return Component => class extends Component {
constructor() {
super(...arguments);
this._queryWatcher = null;
this._querySubscription = null;
}
componentDidMount() {
if (super.componentDidMount) {
super.componentDidMount(...arguments);
}
this._watchOrUpdateQuery(this.props, this.state);
}
componentDidUpdate() {
if (super.componentDidUpdate) {
super.componentDidUpdate(...arguments);
}
this._watchOrUpdateQuery(this.props, this.state);
}
componentWillUnmount() {
if (super.componentWillUnmount) {
super.componentWillUnmount(...arguments);
}
if (this._querySubscription) {
this._querySubscription.unsubscribe();
}
delete this._querySubscription;
delete this._queryWatcher;
}
_watchOrUpdateQuery = (props, state) => {
if (shouldSkip(props, state)) {
return;
}
const options = {
query: evalQuery(props, state),
variables: evalVariables(props, state),
};
if (optionsEqual(options, this.prevOptions)) {
return;
}
this.prevOptions = { ...options };
if (this._queryWatcher) {
this._queryWatcher.setOptions(options);
} else {
this._queryWatcher = client.watchQuery(options);
this._querySubscription = this._queryWatcher.subscribe({
next: this._updateResult,
error: this._updateResult,
});
}
this._updateResult();
}
_updateResult = () => {
if (!this._queryWatcher) {
return;
}
const result = this._queryWatcher.currentResult();
// const r = _.get(result, "data.requests", []);
// console.log(_.map(r, "id"));
this.prevProps = _.assign({}, this.props);
_.assign(this.props, result);
this._unsafeCallUpdate = true;
this.setState({}, function () {
delete this._unsafeCallUpdate;
});
}
};
}```
周末我发个包出来
@janpo
你还需要这个 http link
const httpLink = new HttpLink({
uri: SERVER_URL + "/graphql",
fetch: (url, { body, method }) =>
Taro.request({
url,
header: createHeaders(),
method,
data: body,
dataType: "text",
}).then(response => ({
text: () => Promise.resolve(response.data),
})),
});
@kdong007 发个包出来吧,thx
@janpo 你先copy到自己project里用着
import ApolloClient from 'apollo-boost';
import Taro, { ENV_TYPE } from '@tarojs/taro';
//apollo-client默认支持fetch api,但微信小程序不支持fetch,所以需改造Taro.request,等同于wx.request
const fetch = (url, { body: data, ...fetchOptions }) => {
//Taro.request默认会对res做JSON.parse,但apollo-http-link需要text,也要做一次JSON.parse
//所以要让微信返回text,需做如下配置:dataType: 'txt', responseType: 'text'
//dataType String 否 json 如果设为json,会尝试对返回的数据做一次 JSON.parse
//responseType String 否 text 设置响应的数据类型。合法值:text、arraybuffer
return Taro.request({ url, data, ...fetchOptions, dataType: 'txt', responseType: 'text' })
.then((res) => {
res.text = () => Promise.resolve(res.data)
return res
})
}
const uri = `http://localhost:8080/graphql`;
const graphqlClient = new ApolloClient(Taro.getEnv() === ENV_TYPE.WEB ? { uri } : { uri, fetch });
"apollo-boost": "^0.1.12",
"graphql": "^0.13.2",
"graphql-tag": "^2.9.2",
@neoscript99 谢谢! 如果能把react-apollo到taro就完美了,不知道你怎么想?
我觉得把graphql查询和react控件揉在一起不是一种好的编程模式,
我目前是通过redux的action调用graphql,react控件只和state发生关系。
https://gist.github.com/neoscript99/e2a469088209fd8d4197b5b6bd739673
这是我用来做graphql查询的工具类,包含了通用的增删改查功能,可以提供给redux的action调用,里面的domain最终对应一张数据库表。
但这个类,仅适合我自己的后台,你有兴趣参考下。@janpo
@neoscript99 你确定你理解了graphql的核心么 graphql不是单纯resolver查询chain这些入门的东西 而是type based caching
多种resolver之间的互相cache 以及mutation之后相关的自动刷新之前query相关的UI组件等 这些才是graphql存在的意义
例如你有一个user下面有帖子posts 按照更新时间排序,每个Post有 content/lastUpdate
产品上假设有三页 个人题列表 / 帖子详细列表 / 修改帖子内容
修改帖子后由于帖子内容和更新时间的更新 导致帖子列表重新排序以及帖子详情刷新
你不绑定组件你怎么做跨页刷新? 全局事件么? 然后各种 on off 然后在event listerner遗漏中无限debug
而真正的graphql 是这样的
个人列表类似于这样
user{
id
post{
id
content
lastUpdate
}
}
帖子详情类似于这样
post{
id
content
lastUpdate
xxx
xxx
}
而修改页面mutation 是类似于这样的
mutation xxx{
editPost(xxx){
id
content
lastUpdate
user{
id
posts{
id
}
}
}
}
一个mutation chain 获取所有更新后需要刷新的每个节点 cache自动更新 触发所有相关UI组件刷洗
apollo client官方的教程你可能需要多研究一下
@neoscript99 apollo cache你可以想象成一个server data的redux 从服务器数据到网络状态到前端状态 全部是一体化state based. this is how react should be
@kdong007
type based caching没研究过,也就是说它能帮助你自动管理好state,确实实用。
@kdong007 已经在关注你的 https://github.com/kdong007/taro-apollo 期望更新!谢谢
@kdong007 taro-apollo近期会放出吗?持续关注中... 谢谢
@janpo 已经发出来了 https://github.com/kdong007/taro-apollo 欢迎来踩
Hello~
您的问题楼上已经提供了解决方案,如果没有更多的问题这个 issue 将在 15 天后被自动关闭。
如果您在这 15 天中更新更多信息自动关闭的流程会自动取消,如有其他问题也可以发起新的 Issue。
Good luck and happy coding~
@janpo 你先copy到自己project里用着
请问下有用过 apollo-link-rest 这个库吗? 在小程序中报错了, 需要一些headers信息。 如果用的 http link 在小程序中可用吗?
@kdong007 请问下有没有相关的小程序这边的处理方式? 使用 apollo-link-http的
@Janice1114 原生小程序么? 不用taro/wepy这些框架的那种
@Janice1114 原生小程序么? 不用taro/wepy这些框架的那种
@kdong007 taro的, 例如怎么基于 apollo-link-http 发送请求给中台获取数据,麻烦帮忙看下。 目前h5是没问题的, 小程序接入apollo 后,fetch请求的时候各种坑
@neoscript99 另外有相关的使用 apollo-link-http 这个相关demo吗? h5中调试ok,但是在小程序中发现有些异常,需要解决一下。 看下是怎么做兼容处理的?
@kdong007 请问下有没有 apollo-link-http 在小程序中使用的相关说明? 包括一些指令或者定制处理的,谢谢
@neoscript99 你确定你理解了graphql的核心么 graphql不是单纯resolver查询chain这些入门的东西 而是type based caching
多种resolver之间的互相cache 以及mutation之后相关的自动刷新之前query相关的UI组件等 这些才是graphql存在的意义
例如你有一个user下面有帖子posts 按照更新时间排序,每个Post有 content/lastUpdate
产品上假设有三页 个人题列表 / 帖子详细列表 / 修改帖子内容
修改帖子后由于帖子内容和更新时间的更新 导致帖子列表重新排序以及帖子详情刷新
你不绑定组件你怎么做跨页刷新? 全局事件么? 然后各种 on off 然后在event listerner遗漏中无限debug
而真正的graphql 是这样的
个人列表类似于这样user{ id post{ id content lastUpdate } }帖子详情类似于这样
post{ id content lastUpdate xxx xxx }而修改页面mutation 是类似于这样的
mutation xxx{ editPost(xxx){ id content lastUpdate user{ id posts{ id } } } }一个mutation chain 获取所有更新后需要刷新的每个节点 cache自动更新 触发所有相关UI组件刷洗
apollo client官方的教程你可能需要多研究一下
跨页刷新那地方我不太理解,redux不是很简单可以做到吗,修改帖子内容后出发action改变store的状态,然后列表和详情会rerender更新。
@dpyzo0o redux是可以做到 但是你的工作量非常之大
apollo cache是个对graphql专用的redux
举例你有个数据User如下:
{
id:xxx
name:xxx
age:xxx,
address:{
unitNumber:xxx
streetName:xxx
city:xxxx
}
meta:{
groupA:{
a1:xx
a2:xxx
a3:xxx
}
groupB:{
b1:xx
b2:xx
b3:xx
}
}
}
你的产品在使用过程中会遇到User下的一个或者多个节点数据更新,比如可能是用户自己修改过的,也有可能是服务器上的控制的数据
假如你存一份你自己的User在redux中
首先你要下载自己的数据,那问题就是你第一次下载在哪里?主页启动?但如果你的程序中加入deep link 直接进入的分页,自己的数据还是空 你还要特殊处理
第二 每次更新数据后你都要同步到redux 你用什么方式同步?
更新数据后自己检查修改了哪些节点 然后各种 dispatch actionMyXXXUpdated()? 而且在你后期User数据节点变多的时候你会有无数个小的action
另一种做法 dispatch actionMyUserDataMayUpdate() 整个user丢进去? 那你所有跟User下节点connect的组件都可能出发刷新,你需要写一个非常聪明的merge以及connect的方式要非常小心
也就是说 graphql之后同步到redux的方式可以达到你要的目的,但是比较烦 难于管理
相反 假如你直接用react apollo绑定query, apollo cache知道你的这个组件下面需要具体哪些节点的数据,在别的其他query或者mutation时候,跟回来的数据(一般都是更新后的数据)会先进入apollo cache进行diff/merge,也就上面提到的工作,然后再检查现在的组件中哪些连接的数据节点有更新,然后通知他们刷新。
@kdong007 很详细的回答,谢谢~ apollo我还是刚接触,很多地方理解的还不够深入
Most helpful comment
@janpo 拿走别客气
仿照react-apollo 1.x版做的
client是个apollo client 你可以放个静态变量或者import
```
function optionsEqual(op1, op2) {
if (_.isEmpty(op1) && _.isEmpty(op2)) {
return true;
}
if (_.isEmpty(op1) || _.isEmpty(op2)) {
return false;
}
}
export function withQuery(config = {}) {
const {
query: configQuery,
variables: configVariables,
} = config;
}```