Skip to content
This repository has been archived by the owner on Jul 10, 2019. It is now read-only.

how to manage single values in the store #10

Closed
barbalex opened this issue Nov 13, 2017 · 5 comments
Closed

how to manage single values in the store #10

barbalex opened this issue Nov 13, 2017 · 5 comments

Comments

@barbalex
Copy link
Contributor

I am very new to graphql and apollo. So please excuse if this question seems trivial. Also this may well be the wrong place to ask as it surely is a general graphql question. But it applies for me only when working with local state.

I am trying to use apollo-link-state to replace my mobx store.

In this store there are a number of simple variables, for instance: activeObject. Which is the id of the object presently shown in the detail page.

Your example shows managing local state for a list or array of todos.

Somehow I have not been able to grasp how I would manage state for a single value, such as activeObject.

Of course I can use an array containing only a single value. But that seems just wrong.

How would one manage single values in the store?

@barbalex
Copy link
Contributor Author

barbalex commented Nov 13, 2017

Got it:

import { withClientState } from 'apollo-link-state'
import gql from 'graphql-tag'

const activeObjectQuery = gql`
  query activeObject {
    activeObject @client
  }
`

export default withClientState({
  Query: {
    // provide initial state
    activeObject: null,
  },
  Mutation: {
    // update values in the store on mutations
    setActiveObject: (_, { id }, { cache }) => {
      const data = { activeObject: id }
      cache.writeQuery({ query: activeObjectQuery, data })
      return null
    },
  },
})

and:

const activeObjectMutation = gql`
    mutation setActiveObject($id: String) {
      setActiveObject(id: $id) @client
    }
`
app.client.mutate({
    mutation: activeObjectMutation,
    variables: { id: activeObject.id },
})

@barbalex
Copy link
Contributor Author

barbalex commented Nov 14, 2017

Actually no: Seems that this is not possible: client.readQuery produces:

Uncaught Error: Can't find field activeObject on object (ROOT_QUERY) undefined

@barbalex barbalex reopened this Nov 14, 2017
@barbalex
Copy link
Contributor Author

barbalex commented Nov 14, 2017

Finally got it working by using a single value inside an array for every store variable. Not very elegant :-(

Here my code for two store variables:

Initiate apollo in index.js:

import { ApolloClient } from 'apollo-client'
import { createHttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { ApolloProvider } from 'react-apollo'
import { concat } from 'apollo-link'

import localStateLink from './localStateLink'

const httpLink = createHttpLink({ uri: 'http://localhost:5000/graphql' })
const client = new ApolloClient({
  link: concat(localStateLink, httpLink),
  cache: new InMemoryCache(),
})

localStateLink.js:

import { withClientState } from 'apollo-link-state'

import activeNodeArrayGql from './modules/activeNodeArrayGql'
import activeObjectIdGql from './modules/activeObjectIdGql'

export default withClientState({
  Query: {
    // provide initial state
    activeNodeArray: () => [
      {
        value: ['Taxonomien'],
        __typename: 'ActiveNodeArray',
      },
    ],
    activeObjectId: () => [
      {
        value: null,
        __typename: 'ActiveObjectId',
      },
    ],
  },
  Mutation: {
    // update values in the store on mutations
    setActiveNodeArray: (_, { value }, { cache }) => {
      const data = {
        activeNodeArray: [
          {
            value,
            __typename: 'ActiveNodeArray',
          },
        ],
      }
      cache.writeQuery({ query: activeNodeArrayGql, data })
      return null
    },
    setActiveObjectId: (_, { value }, { cache }) => {
      const data = {
        activeObjectId: [
          {
            value,
            __typename: 'ActiveObjectId',
          },
        ],
      }
      cache.writeQuery({ query: activeObjectIdGql, data })
      return null
    },
  },
})

activeNodeArrayGql.js:

import gql from 'graphql-tag'

export default gql`
  query activeNodeArray {
    activeNodeArray @client {
      value
    }
  }
`

activeObjectIdGql.js:

import gql from 'graphql-tag'

export default gql`
  query activeObjectId {
    activeObjectId @client {
      value
    }
  }
`

Fetching a store variable using getActiveNodeArray.js:

import app from 'ampersand-app'

import activeNodeArrayGql from './activeNodeArrayGql'

export default (): Array<string> => {
  // at startup client is undefined
  if (!app.client) return []
  const result = app.client.readQuery({
    query: activeNodeArrayGql,
  })
  const activeNodeArrayDataset = result.activeNodeArray[0]
  if (!activeNodeArrayDataset) return []
  return activeNodeArrayDataset.value
}

Yuck :-(

activeNodeArray is the url, activeObjectId is the id of the object shown in detail view.

I am glad to hear if someone knows a better way to do this.

@carinakoo
Copy link

carinakoo commented Nov 15, 2017

Here's my functioning code for a simple boolean value:

const ShowFeedbackModalQuery = gql`
  query ShowFeedbackModalQuery {
    showFeedbackModal @client
  }
`

const resolvers = {
  Query: {
    showFeedbackModal: () => false,
  },
  Mutation: {
    toggleFeedbackModal: (root, args, { cache }) => {
      const { showFeedbackModal } = cache.readQuery({ query: ShowFeedbackModalQuery })
      cache.writeQuery({
        query: ShowFeedbackModalQuery,
        data: { showFeedbackModal: !showFeedbackModal },
      })
      return !showFeedbackModal
    },
  },
}

@barbalex
Copy link
Contributor Author

@carinakoo thanks a lot

This puts my examples for a string and array variable to this much nicer code:

Initiate apollo in index.js:

import { ApolloClient } from 'apollo-client'
import { createHttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { ApolloProvider } from 'react-apollo'
import { concat } from 'apollo-link'

import localStateLink from './localStateLink'

const httpLink = createHttpLink({ uri: 'http://localhost:5000/graphql' })
const client = new ApolloClient({
  link: concat(localStateLink, httpLink),
  cache: new InMemoryCache(),
})

localStateLink.js:

import { withClientState } from 'apollo-link-state'

import activeNodeArrayGql from './modules/activeNodeArrayGql'
import activeObjectIdGql from './modules/activeObjectIdGql'

export default withClientState({
  Query: {
    // provide initial state
    activeNodeArray: () => [],
    activeObjectId: () => null,
  },
  Mutation: {
    // update values in the store on mutations
    setActiveNodeArray: (_, { value }, { cache }) => {
      cache.writeQuery({
        query: activeNodeArrayGql,
        data: { activeNodeArray: value },
      })
      return value
    },
    setActiveObjectId: (_, { value }, { cache }) => {
      cache.writeQuery({
        query: activeObjectIdGql,
        data: { activeObjectId: value },
      })
      return value
    },
  },
})

activeNodeArrayGql.js:

import gql from 'graphql-tag'

export default gql`
  query activeNodeArrayQuery {
    activeNodeArray @client
  }
`

activeObjectIdGql.js:

import gql from 'graphql-tag'

export default gql`
  query activeObjectIdQuery {
    activeObjectId @client
  }
`

Fetching a store variable in a component:

import { graphql } from 'react-apollo'
import compose from 'recompose/compose'
... other imports

import activeNodeArrayGql from '../modules/activeNodeArrayGql'

const activeNodeArrayData = graphql(activeNodeArrayGql, {
  name: 'activeNodeArrayData',
})

const enhance = compose(activeNodeArrayData, others)

const MyAppBar = ({
  activeNodeArrayData,
  ...others
}: {
  activeNodeArrayData: Object,
  ...others
}) => {
  const { activeNodeArray } = activeNodeArrayData
  return (<div>my appbar</div>)
}

export default enhance(MyAppBar)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants