我有一个待办事项列表,当从列表中添加或删除项目时,我希望收到通知。
到目前为止,我已经实施了商品添加通知:
<Connect
query={graphqlOperation(listTodos)}
subscription={graphqlOperation(onCreateTodo)}
onSubscriptionMsg={(prev, { onCreateTodo }) => {
return addItem(prev, onCreateTodo)
}}
>
{({ data: { listTodos }, loading, error }) => {
if (loading) return "Loading"
if (error) return "Error"
return listTodos.items
.map(({ id, name }) => <div key={id}>{name}</div>)
}}
</Connect>
现在我想知道如何向该组件添加项目删除通知?订阅属性是否接受一个graphql操作数组?
谢谢!
答案 0 :(得分:0)
您可以在组件中使用多个Connect
组件。
<Connect query={graphqlOperation(listTodos)}>
{({ data: { listTodos }, loading, error }) => {
if (loading) return "Loading"
if (error) return "Error"
return listTodos.items.map(({ id, name }) => <div key={id}>{name}</div>)
}}
</Connect>
<Connect
subscription={graphqlOperation(subscriptions.onCreateTodo)}
onSubscriptionMsg={(prev, { onCreateTodo }) => {
// Do something
return prev;
}}
>
{() => {}}
</Connect>
<Connect
subscription={graphqlOperation(subscriptions.onUpdateTodo)}
onSubscriptionMsg={(prev, { onUpdateTodo }) => {
// Do something
return prev;
}}
>
{() => {}}
</Connect>
答案 1 :(得分:0)
看起来当前的解决方案是按照github问题https://github.com/aws-amplify/amplify-js/issues/4813#issuecomment-582106596
中所述创建自己的Connect组件实现。答案 2 :(得分:0)
我尝试了上面的Connect.ts版本,并在此线程中收到其他人报告的相同错误。因此,我创建了一个版本,您可以按照原始版本将多个订阅作为数组传递-您仍然可以传递单个订阅。 注意:此版本仅需要一个查询和一个onSubscriptionMessage -但是,您的onSubscriptionMessage可以是包装函数,用于检查传递给它的newData并根据此数据调用适当的更新,如下所示:>
const onSubscriptionMessage = (prevQuery, newData) => {
if(newData && newData.onDeleteItem) {
return onRemoveItem(prevQuery, newData);
}
if(newData && newData.onCreateItem) {
return onAddItem(prevQuery, newData);
}
};
针对多个订阅的Connect.ts,它具有一个查询和一个onSubscriptionMessage处理程序,该处理程序根据newData切换处理。
import * as React from 'react';
import { API, GraphQLResult } from '@aws-amplify/api';
import Observable from 'zen-observable-ts';
export interface IConnectProps {
mutation?: any;
onSubscriptionMsg?: (prevData: any) => any;
query?: any;
subscription?: any;
}
export interface IConnectState {
loading: boolean;
data: any;
errors: any;
mutation: any;
}
export class Connect extends React.Component<IConnectProps, IConnectState> {
public subSubscriptions: Array<Promise<GraphQLResult<object>> | Observable<object>>;
private mounted: boolean = false;
constructor(props:any) {
super(props);
this.state = this.getInitialState();
this.subSubscriptions = [];
}
getInitialState() {
const { query } = this.props;
return {
loading: query && !!query.query,
data: {},
errors: [],
mutation: () => console.warn('Not implemented'),
};
}
getDefaultState() {
return {
loading: false,
data: {},
errors: [],
mutation: () => console.warn('Not implemented'),
};
}
async _fetchData() {
this._unsubscribe();
this.setState({ loading: true });
const {
// @ts-ignore
query: { query, variables = {} } = {},
//@ts-ignore
mutation: { query: mutation,
//eslint-disable-next-line
mutationVariables = {} } = {},
subscription,
onSubscriptionMsg = (prevData:any) => prevData,
} = this.props;
let { data, mutation: mutationProp, errors } = this.getDefaultState();
if (
!API ||
typeof API.graphql !== 'function' ||
typeof API.getGraphqlOperationType !== 'function'
) {
throw new Error(
'No API module found, please ensure @aws-amplify/api is imported'
);
}
const hasValidQuery =
query && API.getGraphqlOperationType(query) === 'query';
const hasValidMutation =
mutation && API.getGraphqlOperationType(mutation) === 'mutation';
const validSubscription = (subscription:any) => subscription
&& subscription.query
&& API.getGraphqlOperationType(subscription.query) === 'subscription';
const validateSubscriptions = (subscription:any) => {
let valid = false;
if(Array.isArray(subscription)) {
valid = subscription.map(validSubscription).indexOf(false) === -1;
} else {
valid = validSubscription(subscription)
}
return valid;
};
const hasValidSubscriptions = validateSubscriptions(subscription);
if (!hasValidQuery && !hasValidMutation && !hasValidSubscriptions) {
console.warn('No query, mutation or subscription was specified correctly');
}
if (hasValidQuery) {
try {
// @ts-ignore
data = null;
const response = await API.graphql({ query, variables });
// @ts-ignore
data = response.data;
} catch (err) {
data = err.data;
errors = err.errors;
}
}
if (hasValidMutation) {
// @ts-ignore
mutationProp = async variables => {
const result = await API.graphql({ query: mutation, variables });
this.forceUpdate();
return result;
};
}
if (hasValidSubscriptions) {
// @ts-ignore
const connectSubscriptionToOnSubscriptionMessage = (subscription) => {
// @ts-ignore
const {query: subsQuery, variables: subsVars} = subscription;
try {
const observable = API.graphql({
query: subsQuery,
variables: subsVars,
});
// @ts-ignore
this.subSubscriptions.push(observable.subscribe({
// @ts-ignore
next: ({value: {data}}) => {
const {data: prevData} = this.state;
// @ts-ignore
const newData = onSubscriptionMsg(prevData, data);
if (this.mounted) {
this.setState({data: newData});
}
},
error: (err:any) => console.error(err),
}));
} catch (err) {
errors = err.errors;
}
};
if(Array.isArray(subscription)) {
subscription.forEach(connectSubscriptionToOnSubscriptionMessage);
} else {
connectSubscriptionToOnSubscriptionMessage(subscription)
}
}
this.setState({ data, errors, mutation: mutationProp, loading: false });
}
_unsubscribe() {
const __unsubscribe = (subSubscription:any) => {
if (subSubscription) {
subSubscription.unsubscribe();
}
};
this.subSubscriptions.forEach(__unsubscribe);
}
async componentDidMount() {
this._fetchData();
this.mounted = true;
}
componentWillUnmount() {
this._unsubscribe();
this.mounted = false;
}
componentDidUpdate(prevProps:any) {
const { loading } = this.state;
const { query: newQueryObj, mutation: newMutationObj, subscription: newSubscription} = this.props;
const { query: prevQueryObj, mutation: prevMutationObj, subscription: prevSubscription } = prevProps;
// query
// @ts-ignore
const { query: newQuery, variables: newQueryVariables } = newQueryObj || {};
// @ts-ignore
const { query: prevQuery, variables: prevQueryVariables } =
prevQueryObj || {};
const queryChanged =
prevQuery !== newQuery ||
JSON.stringify(prevQueryVariables) !== JSON.stringify(newQueryVariables);
// mutation
// @ts-ignore
const { query: newMutation, variables: newMutationVariables } =
newMutationObj || {};
// @ts-ignore
const { query: prevMutation, variables: prevMutationVariables } =
prevMutationObj || {};
const mutationChanged =
prevMutation !== newMutation ||
JSON.stringify(prevMutationVariables) !==
JSON.stringify(newMutationVariables);
// subscription
// @ts-ignore
const { query: newSubsQuery, variables: newSubsVars } = newSubscription || {};
// @ts-ignore
const { query: prevSubsQuery, variables: prevSubsVars } = prevSubscription || {};
const subscriptionChanged =
prevSubsQuery !== newSubsQuery ||
JSON.stringify(prevSubsVars) !==
JSON.stringify(newSubsVars);
if (!loading && (queryChanged || mutationChanged || subscriptionChanged)) {
this._fetchData();
}
}
render() {
const { data, loading, mutation, errors } = this.state;
// @ts-ignore
return this.props.children({ data, errors, loading, mutation }) || null;
}
}
/**
* @deprecated use named import
*/
export default Connect;
用法:本文顶部是onSubscriptionMessage的示例。
<Connect
query={graphqlOperation(listTopics)}
subscription={[graphqlOperation(onCreateTopic), graphqlOperation(onDeleteTopic)]}
onSubscriptionMsg={onSubscriptionMessage}>
{.....}
</Connect>