JSPM

  • Created
  • Published
  • Downloads 47
  • Score
    100M100P100Q65772F
  • License MIT

React hooks for hasura-ws

Package Exports

  • @hasura-ws/hooks

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@hasura-ws/hooks) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

@hasura-ws/hooks

Hooks are used together with prepare to offer a react API to consume queries

All hooks takes 3 arguments:

  • the prepared query
  • the variables
  • the inputs passed to useEffect to tell react when to refresh

useQuery

import { initClient } from '@hasura-ws/browser'
import { initPrepare } from '@hasura-ws/prepare'
import { useQuery, isPending, hasError, isReloading } from '@hasura-ws/hooks'

const client = initClient({
  address: 'ws://localhost:8080/v1alpha1/graphql',
  token: 'eyJhbGciOiJIUzI...w5c',
})

const prepare = initPrepare(client)

const getUserEmail = prepare(`query getUserById($id: Int!) {
  user (where: {id: {_eq: $id}}) {
    email
  }
}`)

const MyQueryComponent = ({ id }) => {
  const users = useQuery(getUserEmail, { id }, [id])

  if (isPending(users)) return 'Loading...'
  if (hasError(users)) return 'Oops !'
  if (!users.length) return 'Not found'

  const { email } = users[0]
  return <div class={isReloading(users) ? 'loading' : ''}>{email}</div>
}

// Or using `.one` to get one user directly:
const MyQueryComponent = ({ id }) => {
  const user = useQuery(getUserEmail.one, { id }) // we can also omit inputs

  // Omitted inputs are generated using Object.values(variables),
  // so it is equivalent to [ id ] in that case.

  if (isPending(user)) return 'Loading...'
  if (hasError(user)) return 'Oops !'
  if (!user) return 'Not found'

  return <div>{user.email}</div>
}

useSubscribe

const userSubscribe = prepare(`
subscription subscribeToUserById($id: Int!) {
  user (where: {id: {_eq: $id}}) {
    email
  }
}`)

const MySubscribeComponent = ({ id }) => {
  const user = useSubscribe(userSubscribe.one, { id }, [id])
  if (isPending(user)) return 'Loading...'
  if (hasError(user)) return 'Oops !'
  if (!user) return 'Not found'

  return <div>{user.email}</div>
}

useMutation

// You should try have the useMutation in it's separate component
// so that the pending update doesn't trigger a rerender of the rest
// of your app.
const MyUpdateButton = ({ id, email, showMessage }) => {
  const updateUser = useMutation(updateUserMutation)

  return (
    <button
      disabled={updateUser.pending}
      onClick={
        () =>
          updateUser.run({ id, changes: { email } })
            .then(() => showMessage('update successfull'))
            .catch(err => showMessage(`update failed: ${err.message}`))
            // With mutations, you need to handle errors manualy
            // they arent catched and passed for you.
      }
    />
  )
}

const MyMutationComponent = ({ id }) => {
  const [email, setEmail] = useState()
  const [message, setMessage] = useState('')

  return (
    <div>
      <input value={email} onChange={e => setEmail(e.target.value)} />
      <MyUpdateButton email={email} id={id} setMessage={message} />
      <pre>{message}</pre>
    </div>
  )
}

prepareWithHooks

A prefered version of prepare that also add hooks to your query.

import { initClient } from '@hasura-ws/browser'
import { initPrepareWithHooks, hasError, isPending } from '@hasura-ws/hooks'

const client = initClient({
  address: 'ws://localhost:8080/v1alpha1/graphql',
  token: 'eyJhbGciOiJIUzI...w5c',
})

const prepare = initPrepareWithHooks(client)

const userSubscribe = prepare(`
subscription subscribeToUserById($id: Int!) {
  user (where: {id: {_eq: $id}}) {
    email
  }
}`)

// prepare hooks gives a hook for each prepare methods:
// use, useOne, useAll and useMap.

// Here an example of useOne:
const MySubscribeComponent = ({ id }) => {
  const user = userSubscribe.useOne({ id })
  if (isPending(user)) return 'Loading...'
  if (hasError(user)) return 'Oops !'
  if (!user) return 'User not found !'

  return <div>{user.email}</div>
}

buildModelWithHooks

import { initClient } from '@hasura-ws/browser'
import { buildModelWithHooks, initPrepareWithHooks } from '@hasura-ws/hooks'

const client = initClient({
  address: 'ws://localhost:8080/v1alpha1/graphql',
  token: 'eyJhbGciOiJIUzI...w5c',
})

const prepare = initPrepareWithHooks(client)
const model = buildModelWithHooks(prepare)

Using hooks, the model also expose a react hooks for each actions:

  • .useGet(id)
  • .useAdd({ a: 1, b: 2 }, [1, 2])
  • .useRemove(id)
  • .useUpdate({ id, a: 1, b: 2 }, [1, 2])
  • .useSubscribe(id)

It's just the correct hook and the model method.

As such useAdd is useMutation for user.add.

model.useUpdate

const MyComponent = ({ userId }) => {
  const updateUser = userModel.useUpdate()

  return (
    <button
      disabled={updateUser.pending}
      onClick={() => updateUser.run({ id: userId, email: 'jean@mail.com' })}
    />
  )
}

initAll

This can be use to combine prepareWithHooks and buildModelWithHooks

import { initClient } from '@hasura-ws/browser'
import { initAll } from '@hasura-ws/hooks'

const { client, model, prepare } = initAll(initClient({
  address: 'ws://localhost:8080/v1alpha1/graphql',
  token: 'eyJhbGciOiJIUzI...w5c',
}))