Skip to content

Instantly share code, notes, and snippets.

@dabit3
Last active January 26, 2021 16:04
Show Gist options
  • Save dabit3/ee8f489ebc208502ab9351809e96e70d to your computer and use it in GitHub Desktop.
Save dabit3/ee8f489ebc208502ab9351809e96e70d to your computer and use it in GitHub Desktop.
Example of using custom React hooks for managing GraphQL subscriptions
import { useEffect, useState } from 'react'
import { API, graphqlOperation } from 'aws-amplify'
const ListTalks = `
query {
listTalks {
items {
name
description
presenter {
name
bio
}
}
}
}
`
const OnCreateTalk = `
subscription {
onCreateTalk {
id
name
description
presenter {
name
bio
}
}
}
`
export default () => {
const [talks, updateTalks] = useState([])
useEffect(async() => {
const talkData = await API.graphql(graphqlOperation(ListTalks))
updateTalks(talkData.data.listTalks.items)
}, [])
useEffect(() => {
const subscription = API.graphql(
graphqlOperation(OnCreateTalk)
).subscribe({
next: data => {
const { value: { data: { onCreateTalk } }} = data
const talkData = [...talks, onCreateTalk]
updateTalks(talkData)
}
})
return () => subscription.unsubscribe()
}, [talks])
return talks
}
@kristianmandrup
Copy link

I think you could easily make this more generic (factory method), so that you can generate the hook from a set of params

import { useEffect, useState } from "react";
import { API, graphqlOperation } from "aws-amplify";

const ListTalks = `
  query {
    listTalks {
      items {
        name
        description
        presenter {
          name
          bio
        }
      }
    }
  }
`;

const OnCreateTalk = `
  subscription {
    onCreateTalk {
      id
      name
      description
      presenter {
        name
        bio
      }
    }
  }
`;

const createHook = ({
  onChange,
  onChangeName,
  queryName,
  hasItems,
  triggerOn
}) => {
  if (!Array.isArray(triggerOn) && triggerOn.length > 0) {
    new Error(
      "Must take a triggerOn option with an non-empty array of variables that the hook should be triggered on"
    );
  }

  return () => {
    const [queryData, updateData] = useState([]);

    useEffect(async () => {
      const result = await API.graphql(graphqlOperation(query));
      const baseData = result.data[queryName];
      const data = hasItems ? baseData.items : baseData;
      updateData(data);
    }, []);

    useEffect(() => {
      const subscription = API.graphql(graphqlOperation(onChange)).subscribe({
        next: data => {
          const {
            value: {
              data: { onChangeName }
            }
          } = data;
          const result = [...queryData, onChangeName];
          updateData(result);
        }
      });

      return () => subscription.unsubscribe();
    }, applyOnChangedData);
    return queryData;
  };
};

const useSubscription = createHook({
  onChange: onCreateTalk,
  query: ListTalks,
  queryName: "listTalks",
  onChangeName: "onCreateTalk",
  hasItems: true,
  triggerOn: [talks]
});

@kristianmandrup
Copy link

I would further recommend leveraging Apollo Client to do much of the "heavy lifting" ;)

@Scotthorn0
Copy link

@kristianmandrup Would you mind clarifying what you mean by "heavy lifting"?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment