{"id":25667251,"url":"https://github.com/nostackapp/no-stack","last_synced_at":"2025-04-22T21:32:31.180Z","repository":{"id":35110001,"uuid":"206304696","full_name":"NoStackApp/no-stack","owner":"NoStackApp","description":"React client for NoStack services","archived":false,"fork":false,"pushed_at":"2023-01-07T09:33:58.000Z","size":3005,"stargazers_count":2,"open_issues_count":31,"forks_count":1,"subscribers_count":2,"default_branch":"alpha","last_synced_at":"2025-04-14T21:06:18.480Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://www.nostack.net","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NoStackApp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-09-04T11:36:10.000Z","updated_at":"2021-08-01T12:19:12.000Z","dependencies_parsed_at":"2023-01-15T14:15:17.408Z","dependency_job_id":null,"html_url":"https://github.com/NoStackApp/no-stack","commit_stats":null,"previous_names":[],"tags_count":33,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NoStackApp%2Fno-stack","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NoStackApp%2Fno-stack/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NoStackApp%2Fno-stack/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NoStackApp%2Fno-stack/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NoStackApp","download_url":"https://codeload.github.com/NoStackApp/no-stack/tar.gz/refs/heads/alpha","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250328760,"owners_count":21412680,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-02-24T09:28:29.244Z","updated_at":"2025-04-22T21:32:31.147Z","avatar_url":"https://github.com/NoStackApp.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @nostack/no-stack\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)\n\nNOTE: this is being released in ALPHA. Not yet stable!!\n\n`no-stack` lets you build a full stack application using nothing but static front\nend code. You can even run it without a server, for instance using an AWS S3 bucket\nenabled as an endpoint.\n\nTo get the full value of `no-stack`, you need to register a platform. Currently,\nyou must do that at [www.nostack.net](www.nostack.net).\n\nThen, you can build your virtual back end in one of two ways. (1) You can use our\napi (api.matchlynx.com). (2) You can run your app as a user with \"moderator\" status.\n\nYou start by declaring types of users called user classes. Then, you give each class\nactions. You can build whatever pages you like. You can declare and use data `Types`\nwhich have `Instances`. `Types` also have `Assns` (associations) between each other.\n\nA page can use data via `Units`. Each unit has some minimal necessary `Assns`\nand the `Types` that you need. You can also create `Constraints` on the `Instances`\nreturned.\n\nThis repository contains the `no-stack` helper components and functions.\n\n## Getting Started\n\n### Prerequisites\n\nBe sure you have the latest stable version of [Node \u0026 NPM](https://nodejs.org/en/download/)\ninstalled. Depending on your machine, you would probably need to\n[fix permissions for NPM](https://stackoverflow.com/questions/16151018/npm-throws-error-without-sudo).\n\nYou might also need to install [TypeScript](https://www.typescriptlang.org/#download-links)\nglobally.\n\n### Install Dependencies\n\n`no-stack` requires React \u0026 Apollo as dependencies.\n\nTo install React, use `create-react-app` and bootstrap your app by following\n[these directions](https://facebook.github.io/create-react-app/docs/getting-started).\n\nThen `cd` into your app folder and install Apollo:\n\n```bash\nnpm install @apollo/react-common @apollo/react-components @apollo/react-hoc \\\n  @apollo/react-hooks @shopify/react-compose apollo-cache-inmemory \\\n  apollo-client graphql apollo-link --save\n```\n\nInstall the rest of `no-stack`'s dependencies:\n\n```bash\nnpm install apollo-fetch apollo-link-context apollo-link-http axios formik \\\n  graphql-tag jsonwebtoken react-graph-vis react-spinkit styled-components \\\n  uuid --save\n```\n\n### Install `no-stack` via NPM/Yarn\n\n```bash\nnpm install @nostack/no-stack --save\n```\n\n### Initial Set-Up\n\nThis guide will create a basic set-up for your React \u0026 Apollo instances. If you need\na more complicated set-up, please refer to their respective official documentation.\n\n#### Setting up React and Apollo\n\nEdit `src/index.js` file like so:\n\n```javascript\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport { ApolloProvider } from 'react-apollo';\n\nimport './index.css';\n\nimport client from './client'; // we will create this file\nimport App from './App';\nimport * as serviceWorker from './serviceWorker';\n\n// wrap your app inside ApolloProvider\nReactDOM.render(\n  \u003cApolloProvider client={client}\u003e\n    \u003cApp /\u003e\n  \u003c/ApolloProvider\u003e,\n  document.getElementById('root'),\n);\n\n// If you want your app to work offline and load faster, you can change\n// unregister() to register() below. Note this comes with some pitfalls.\n// Learn more about service workers: http://bit.ly/CRA-PWA\nserviceWorker.unregister();\n```\n\nThen edit `src/client/index.js`:\n\n```javascript\nimport { ApolloClient } from 'apollo-client';\nimport { ApolloLink } from 'apollo-link';\nimport { InMemoryCache } from 'apollo-cache-inmemory';\nimport { v4 } from 'uuid';\n\nimport { createAuthLink, httpLink } from '@nostack/no-stack';\n\nconst PLATFORM_ID = 'your-platform-id';\n\nconst authLink = createAuthLink(PLATFORM_ID);\n\nconst link = ApolloLink.from([authLink, httpLink]);\n\nexport default new ApolloClient({\n  link,\n  cache: new InMemoryCache({\n    dataIdFromObject: object =\u003e\n      object.id ? object.id + object.__typename : v4(),\n  }),\n});\n```\n\n#### Cache Set-Up\n\nTo allow `no-stack`'s helper functions (discussed below) to access and update\nApollo's cache, `dataIdFromObject` must be set up like we did above, which we\nrepeat here:\n\n```javascript\nimport { v4 } from 'uuid';\n\nconst client = new ApolloClient({\n  // ...other options...\n  cache: new InMemoryCache({\n    // ... other options ...\n    dataIdFromObject: object =\u003e\n      object.id ? object.id + object.__typename : v4(),\n  }),\n});\n```\n\n#### Bootstrapping Your Application\n\nTo enable `no-stack`'s features in your application, you need to replace\n`\u003cApolloProvider\u003e` with `\u003cNoStackProvider\u003e` component. You may do so by adding\nit in our previous `src/index.js` file like so:\n\n```javascript\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport { NoStackProvider } from '@nostack/no-stack';\n\nimport './index.css';\n\nimport client from './client'; // we will create this file\nimport App from './App';\nimport * as serviceWorker from './serviceWorker';\n\nconst PLATFORM_ID = 'your-platform-id';\n\n// wrap your app inside NoStackProvider\n// then wrap NoStackProvider inside ApolloProvider\nReactDOM.render(\n  \u003cNoStackProvider client={client} platformId={PLATFORM_ID}\u003e\n    \u003cApp /\u003e\n  \u003c/NoStackProvider\u003e,\n  document.getElementById('root'),\n);\n\n// If you want your app to work offline and load faster, you can change\n// unregister() to register() below. Note this comes with some pitfalls.\n// Learn more about service workers: http://bit.ly/CRA-PWA\nserviceWorker.unregister();\n```\n\n`\u003cNoStackProvider\u003e` uses Apollo's `\u003cApolloProvider\u003e` under the hood.\n\nThe only required props of `\u003cNoStackProvider\u003e` is your `platformId`\nand the `client`.\n\n## Usage\n\n### Authentication\n\n`no-stack` provides a helper components, `\u003cLoginForm\u003e` \u0026 `\u003cLogoutButton\u003e` to automate\nlogin \u0026 logout. Sample usage:\n\n```javascript\nimport React from 'react';\nimport { LoginForm, LogoutButton } from '@nostack/no-stack';\n\nconst SomeComponent = () =\u003e (\n  \u003cNoStackConsumer\u003e\n    {({ currentUser, loading }) =\u003e {\n      if (loading) return 'Loading...';\n\n      if (!currentUser) {\n        return \u003cLoginForm /\u003e;\n      }\n\n      return \u003cLogoutButton /\u003e;\n    }\n  \u003c/NoStackConsumer\u003e\n);\n\nexport default SomeComponent;\n```\n\nNote: `\u003cLogoutButton\u003e` hides itself automatically if user is not logged in.\n\n#### `\u003cNoStackConsumer\u003e` Component\n\nTo access the authentication state of the user, you will need `\u003cNoStackConsumer\u003e`.\nSample usage was illustrated above.\n\nIt also provides some helper methods if you want to customize your login/logout\nbehavior.\n\n##### `\u003cNoStackConsumer\u003e` Function as a Child (FAAC) Props\n\n- `platformId` - The current platform's ID\n\n- `currentUser` - The current user object\n  `{id: 'some-id', name: 'some-name', role: 'some-role'}`\n\n- `loading` - Boolean. `true` if currently validating user with API.\n\n- `login({ username: 'some-username', password: 'some-password' })` - Helper function\n  to log in a user with credentials. If successful, it sets `currentUser` and stores\n  auth tokens in browser's `localStorage`.\n\n- `logout(callback)` - Helper function to log out user. Removes `currentUser`\n  and all auth tokens. Executes provided callback function after logout.\n\n##### Alternative: `withNoStack` Higher Order Component\n\nYou may interchage `\u003cNoStackConsumer\u003e` with `withNoStack` HOC and achieve the\nsame effect:\n\n```javascript\nimport { withNoStack } from '@nostack/no-stack';\n\nconst SomeComponent = ({ currentUser, loading, login, logout }) =\u003e {\n  if (loading) return 'Loading...';\n\n  if (!currentUser) {\n    return \u003cLoginForm onSubmit={login} /\u003e;\n  }\n\n  return \u003cLogoutButton onClick={logout} /\u003e;\n};\n\nexport default withNoStack(SomeComponent);\n```\n\n`withNoStack` also provides the same props that `\u003cNoStackConsumer\u003e`'s FAAC provides.\nFeel free to use either, whatever suits your preference or situation.\n\n### User Registration\n\n`no-stack` provides a `\u003cRegistrationForm\u003e` component for your app's user registration:\n\n```javascript\nimport { PLATFORM_ID, TYPE_USER_ID } from './config';\n\nexport default SomeComponent = () =\u003e (\n  \u003cdiv\u003e\n    \u003cRegistrationForm platformId={PLATFORM_ID} userClassId={TYPE_USER_ID} /\u003e\n  \u003c/div\u003e\n);\n```\n\n#### `\u003cRegistrationForm\u003e` Props\n\n- `plantformId` - The current platform's ID\n\n- `userClassId` - The user class ID of the user to be created\n\n- `onSuccess(data)` - Callback function that will be invoked upon successful registration\n\n### Data Retrieval via the `\u003cUnit\u003e` Component (Experimental)\n\n`no-stack` provides a `\u003cUnit\u003e` component for retrieving data.\n`no-stack` uses GraphQL. See this [Intro to GraphQL](https://graphql.org/learn/)\nfor more info about using GraphQL, and\n[GraphQL Queries](https://graphql.org/learn/queries/) in particular.\n\nThe `no-stack` `Unit` Component is very close to the\n[Apollo Client Query Component](https://www.apollographql.com/docs/react/api/react-components/#query).\nBoth take the same prop of a `query`.\n\nFollowing is an example usage.\n\n```javascript\nimport React from 'react';\nimport { Unit } from '@nostack/no-stack';\nimport gql from 'graphql-tag';\n\nconst UNIT_QUERY = gql`\n  query UNIT(\n    $id: ID!\n    $typeRelationships: String!\n    $parameters: String\n    $unrestricted: Boolean!\n  ) {\n    unitData(\n      unitId: $id\n      typeRelationships: $typeRelationships\n      parameters: $parameters\n      unrestricted: $unrestricted\n    ) {\n      instance {\n        id\n        value\n        type\n      }\n      children {\n        instances {\n          instance {\n            id\n            value\n            type\n          }\n          children {\n            instances {\n              instance {\n                id\n                value\n                type\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n`;\n\nconst unitId = 'your-unit-id';\n\nconst typeRelationships = {\n  'first-type-id': {\n    'second-type-id': {\n      'third-type-id': null,\n    },\n  },\n};\n\nconst unrestricted = true;\n\nconst YourComponent = ({ someParam }) =\u003e {\n  const parameters = {\n    someParam,\n  };\n\n  return (\n    \u003cUnit\n      id={unitId}\n      typeRelationships={typeRelationships}\n      query={UNIT_QUERY}\n      unrestricted={unrestricted}\n      parameters={parameters}\n    \u003e\n      {({ loading, error, data }) =\u003e {\n        if (loading) {\n          return 'Loading...';\n        }\n\n        if (error) return `Error: ${error.graphQLErrors}`;\n\n        console.log(data);\n\n        return \u003cdiv\u003eTest Unit\u003c/div\u003e;\n      }}\n    \u003c/Unit\u003e\n  );\n};\n\nexport default YourComponent;\n```\n\n#### `\u003cUnit\u003e` Props\n\n- `id` - the unit ID\n\n- `typeRelationships` - the desired return type hierarchy (see below)\n\n- `query` - the GraphQL tagged query string or file (see below)\n\n- `parameters` - an object consisting of key-value pairs representing the required\n  constraints of the unit\n\n- `unrestricted` - boolean; `true` if data is available to public, `false` if\n  otherwise. (default: false)\n\n#### `typeRelationships` Prop\n\nA unit can be thought of as a virtual table, like a view in a relational database.\nEach type is like a column. In relational terms, the `typeRelationships` prop is\nlike a \"projection\" (letting you specify which of the \"columns\" (types) you want\nreturned in your request.\n\nBut, unlike with a table, the data returned here is a hierarchy, where a child type's\ninstances are grouped based on the parent type's instances. So when you specify what\nyou want, you must start with the highest level of that hierarchy (the root), and\nthen list it's children (if any). You then do the same recursively for each subtree.\n\nTherefore, the `typeRelationships` is tree, specified as a JSON. The format is as\nfollows:\n\n```json\n{\n  \u003cparentType\u003e: {\n    \u003cchild1\u003e: {\n      \u003cchild1a\u003e: \u003cchild1a-subtree\u003e,\n      \u003cchild1b\u003e: \u003cchild1b-subtree\u003e,\n      ...\n    },\n    \u003cchild2\u003e: {\n      \u003cchild2a\u003e: \u003cchild2a-subtree\u003e,\n      \u003cchild2b\u003e: \u003cchild2b-subtree\u003e,\n      ...\n    },\n    ...\n  },\n}\n```\n\nThe simplest case would be a single type with no children:\n`{ doctor_type_id: {} }`. In this case, doctor has no child.\n\nA bit more complex would be a type with one child:\n`{ doctor_type_id: { nurse_type_id: {}, patient_type_id: {} }}`. In this case,\neach doctor will be returned with children including nurses for each doctor and patients\nfor each doctor.\n\nA third possibility is this:\n\n```json\n{\n  \"doctor_type_id\": {\n    \"nurse_type_id\": {\n      \"patient_type_id\": {}\n    }\n  }\n}\n```\n\nNote that here each doctor will have nurses, and each nurse will have patients.\n\nUsually, a `typeRelationships` won't be large at all. (That's probably better style\nanyway. In general, `no-stack` encourages minimizing state on the front end.)\n\nSome important notes:\n\n- If a type does not have child types, represent it by setting the type to `{}`.\n\n- Neither the choice of fields nor their place in the hierarchy will constrain the\n  data returned. The data for a unit at any given moment is fixed, and the type\n  hierarchy simply selects what columns are returned and the grouping. For example,\n  say that a unit contains a set of doctors, nurses, and patients. Then all of\n  the doctors contained in that unit will be returned whether the type hierarchy\n  has just doctors or doctors and nurses. The reason is that if a doctor had no nurses\n  than he or she would not be included in the unit in the first place.\n\n- That said, the data returned is distinct within the selected sets. So a small\n  `typeRelationships` might well return fewer instances than a larger one. The rule\n  is that each instance of the root type appears only once, and each instance of\n  a child type appears only once for its parent instance. For instance, if Doctor\n  A has ten nurses, then listing by doctor as the root would show Doctor A once with\n  all ten of his nurses, whereas listing by nurse first would show the same doctor\n  ten times, once for each nurse.\n\n#### `query` Prop\n\nAs stated above, The `Unit` Component is very close to the\n[Apollo Client Query Component](https://www.apollographql.com/docs/react/api/react-components/#query).\nBoth take the same prop of a `query`.\n\nThe query prop is the actual query to use. In the case above, it is a `gql` specification.\nIn addition, you can provide a file that includes the complete query specification.\n\nThe plan in the near future is to generate such files for you, which you can then\ninsert into your project. In the meantime, you must generate it yourself.\n\nFundamentally, the query `unitData` is called with four variables (which is provided\nby `Unit`'s props discussed above):\n\n```graphql\n  $id: ID!\n  $typeRelationships: String!\n  $parameters: String\n  $unrestricted: Boolean!\n```\n\n#### Fields requested\n\nA call to a GraphQL API allows you as the developer to decide which specific \"fields\"\nyou want to request to be part of the returned data.\n\n`no-stack` uses GraphQL. See [GraphQL Query Fields](https://graphql.org/learn/queries/#fields)\nfor an introduction.\n\nSpecifically, information about the instances for types in your `typeHiearchy` are\nreturned. For each returned instance you can choose from the following fields in\nyour `unitData` request:\n\n```graphql\n{\n  id\n  type\n  instance {\n    id\n    value\n    type\n    order\n  }\n  children {\n    ...\n  }\n}\n```\n\nThe `children` field can recursively contain any of these same fields as deeply as\nyou desire up to the depth of its `typeRelationships`.\n\nThe meaning of the fields is as follows:\n\n- `typeId` - current type's id\n\n- `instances` - an array of instances of the given typeId\n\nHere is an example of the fields requested. This json specifies all of the data\nto a depth of 3:\n\n```graphql\n{\n  id\n  type\n  instance {\n    id\n    value\n    order\n  }\n  children {\n    typeId\n    instances {\n      instance {\n        id\n        value\n        type\n        order\n      }\n      children {\n        typeId\n        instances {\n          instance {\n            id\n            value\n            type\n            order\n          }\n        }\n      }\n    }\n  }\n}\n```\n\nIn general, you should request up to the depth of your `typeRelationships` (see above).\nAnything less will be missing data, and anything more will not return anything.\n\n#### `\u003cUnit\u003e` Function as a Child (FAAC) Props\n\n- `loading` - boolean; `true` if data is still being fetched, `false` if otherwise.\n- `error` - error object; `null` if there's operation succeeds.\n- `data` - the data object.\n- `queryVariables` - object containing the props provided to the `\u003cUnit\u003e` (refer\n  to discussion above).\n- `refetchQueries` - a single element array containing the object to be fed to Apollo\n  mutation's own `refetchQueries`property (see mutation discussion below).\n- `updateUnitAfterCreateAction(instance)` - a higher-order function function for\n  updating Apollo cache after creating an instance (see mutation discussion below).\n- `updateUnitInstanceAfterUpdateAction(instanceId, fragment)` - a higher-order function\n  for updating an instance in Apollo cache after updating an instance (see mutation\n  discussion below).\n- `updateUnitAfterDeleteAction(instanceId)` - a higher-order function for updating\n  Apollo cache after deleting an instance (see mutation discussion below).\n\n#### `\u003cUnit\u003e` Inspector\n\nIn addition to data retrieval, the `\u003cUnit\u003e` component also has a data inspector\nmodal that is accessible to any logged-in platform moderator.\n\nYou don't have to do anything special in your code to enable this feature. Once you're\nlogged in as a moderator via `\u003cNoStackConsumer\u003e`, a button with the plus (+) sign\nwill show on every instance of the `\u003cUnit\u003e` component on the current page.\n\nThe inspector currently only shows the relationships between types of data (nodes)\nvia a type tree graph visualization. But you will eventually be able to manage your\ndata type tree (i.e. add/remove types) using the inspector.\n\n### Manipulating Data via Action Mutations (Experimental)\n\nCurrently, data manipulation uses Apollo's GraphQL components. `no-stack` provides\na mutation helper you can plug into Apollo's `\u003cMutation\u003e` component called `EXECUTE_ACTION`:\n\n```javascript\nimport { Mutation } from '@apollo/react-components';\nimport { EXECUTE } from '@nostack/no-stack';\n\nconst YourComponent = () =\u003e (\n  \u003cMutation mutation={EXECUTE} \u003e\n  {(executeAction, { data }) =\u003e\n    if (data) {\n      console.log(data);\n    }\n\n    return (\n      \u003cdiv\u003e\n        \u003cbutton onClick={() =\u003e executeAction({\n            variables: {\n              actionId: 'dummy-id',\n              executionParameters: JSON.stringify({ someParameter: 'value' }),\n              unrestricted: false,\n            },\n        })}\u003e\n          Execute Action\n        \u003c/button\u003e\n      \u003c/div\u003e\n    );\n  }\n  \u003c/Mutation\u003e\n);\n```\n\nOr, via Apollo's `graphql` HOC:\n\n```javascript\nimport { graphql } from '@apollo/react-hoc';\nimport { EXECUTE } from '@nostack/no-stack';\n\nconst YourComponent = ({ executeAction }) =\u003e (\n  \u003cdiv\u003e\n    \u003cbutton onClick={async () =\u003e {\n      const { data } = await executeAction({\n        variables: {\n          actionId: 'dummy-id',\n          executionParameters: JSON.stringify({ someParameter: 'value' }),\n          unrestricted: false,\n        },\n      });\n\n      console.log(data);\n    }\u003e\n      Execute Action\n    \u003c/button\u003e\n  \u003c/div\u003e\n);\n\nexport default graphql(\n  EXECUTE,\n  {\n    name: 'executeAction',\n  },\n)(YourComponent);\n```\n\nDepending on its type, the action called with `EXECUTE` can perform different\nmutations, including but not limited to creating/updating/deleting instances, logging\nin/out, and user registration.\n\n#### EXECUTE SIGNATURE\n\n| Variable            | Description                                                             | Value                                                      | Required              |\n| ------------------- | ----------------------------------------------------------------------- | ---------------------------------------------------------- | --------------------- |\n| actionId            | An existing action ID                                                   | ID                                                         | Yes                   |\n| executionParameters | An object describing the optional and required parameters of the action | Valid JSON String (use `JSON.stringify()`)                 | Depends on the action |\n| unrestricted        | Signifies if the action authorization                                   | `true` if restricted to logged in users (default: `false`) | No                    |\n\n### Updating Apollo Cache After Action Mutations\n\nApollo implements a front end store for all GraphQL queries that get executed which\nthey call the \"cache\".\n\nUsually, after calling GraphQL mutations, or particularly in `no-stack`'s case, action\nmutations, the data on the backend and on the Apollo Cache become out of sync. To\nkeep Apollo Cache in sync, [you need to access it directly](https://www.apollographql.com/docs/react/advanced/caching/#direct-cache-access).\n\nTo help make this process easier, no-stack's `\u003cUnit\u003e` component provides a few\nhelpers via its render props. (Note: Sample usage code is from the demo [Todo App](https://github.com/NoStackApp/stackbox-todo).)\n\n#### `refetchQueries`\n\n`refetchQueries` is an array to be used with\n[Apollo mutation's `refetchQueries` props](https://www.apollographql.com/docs/react/api/react-apollo/#optionsrefetchqueries).\nThis is the most convenient way of updating the Apollo cache. But it is also the\nslowest, since it requires making a roundtrip HTTP transaction with the `no-stack`\nAPI.\n\nFor usage, see [`\u003cCreateIsCompletedForm\u003e`](https://github.com/NoStackApp/stackbox-todo/blob/non-root-list-type/src/components/CreateIsCompletedForm/index.js#L40).\n\n#### `updateUnitAfterCreateAction(instance)`\n\n`updateUnitAfterCreateAction` is a higher-order function that returns a function\nthat fits the signature for the callback used by [Apollo mutation's `update` property](https://www.apollographql.com/docs/react/api/react-apollo/#optionsupdate).\nAs the function name suggests, this is mostly suitable after an action that creates\nan instance.\n\nFor sample usage, see [`\u003cCreateProjectForm\u003e`](https://github.com/NoStackApp/stackbox-todo/blob/yisroel/src/components/CreateProjectForm/index.js#L43).\nNote: `\u003cCreateProjectForm\u003e`'s parent passes it `updateUnitAfterCreateAction` as\nthe `onAdd` prop.\n\nA slightly more complicated usage is found in [`\u003cCreateTodoForm\u003e`](https://github.com/NoStackApp/stackbox-todo/blob/yisroel/src/components/CreateTodoForm/index.js#L79).\n\n#### `updateUnitInstanceAfterUpdateAction(instanceId, fragment)`\n\n`updateUnitInstanceAfterUpdateAction` is similar to `updateUnitAfterCreateAction`,\nbut it is meant to be used for updating a given instance in the cache after an\naction that updates it on the backend.\n\nFor sample usage, see [`\u003cProject\u003e`](https://github.com/NoStackApp/stackbox-todo/blob/yisroel/src/components/Project/index.js#L57).\n\n#### `updateUnitAfterDeleteAction(instanceId)`\n\n`updateUnitAfterDeleteAction` is similar to `updateUnitAfterDeleteAction`, but\nit is meant to be used for updating the cache after an action that deletes an instance.\n\nFor sample usage, see [`\u003cProject\u003e`](https://github.com/NoStackApp/stackbox-todo/blob/yisroel/src/components/Project/index.js#L75).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnostackapp%2Fno-stack","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnostackapp%2Fno-stack","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnostackapp%2Fno-stack/lists"}