Giter Site home page Giter Site logo

react-hooks-api's People

Contributors

arnaudweyts avatar dependabot[bot] avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-hooks-api's Issues

Add useMutation hook

How does it work

  • Used for adding, updating or deleting an entity.

Let's make sure we have an entity store first (#3)

RFC: non-standard CRUD endpoints in the entity store

What

This proposal is related to #13.

There's a working implementation of #13, but we never discussed non-conventional CRUD endpoints like .report or other future endpoints. How do we handle calculation endpoints like these? Where do they belong in the store?

This RFC served more as a write-up for myself and documentation. Scroll down to see the actual proposal.

Proposal

Storing the returned data

Our store is a normalized entity store. This means entities are stored using a unique identifier. In our case: their UUID. What gets returned from f.e. projectItems.report is:

{
  "data": {
    "billableAmount": {
       "amount": 1644.65,
       "currency": "EUR"
     },
    "result": {
       "amount": -195.35,
       "currency": "EUR"
    },
    "cost": {
       "amount": 1840,
       "currency": "EUR"
    },
    "quantity": 28,
    "type": "tracked_time",
     "unit": "hour",
    "participant": {
      "type": "user",
      "id": "d2886235-61f8-4c77-8e6f-d55f4c91f501"
    }
  }

There's nothing here to really identify this calculation by. As it's "just" a calculation at that point in time. It's not stored in the database, it's not an entity.

So let's first find something to identify this calculation by. We could generate an ID based on the parameters passed in the request body:

In the case of projectItems.report this is

  • milestone_id
  • group_by (an enum)
  • (maybe the timestamp of the request)

While I was writing this down, it dawned on me that we can just store the returned data inside our queries state object. It makes sense, since we're already generating a "unique" id for each query. This makes sure we don't pollute our entity store with calculation data.

So here comes the actual proposal

Only try to store actual entities inside the entities state object. Makes a lot of sense right? Inside of useQuery I'll be adding a check if the action is of the type info or list. And every other action will result in the response being set inside the queries object, under their respective query identifier.

RFC: storing data, sideloading and what to return

What

This proposal will serve as documentation and a place to discuss how the implementation works. What do we return as the data object, how is the data stored under the hood and how is sideloading handled?

Proposal

Already partially implemented in #11.

Storing data

Normalized entities and queries

Entities will be written to a redux store, normalized by id. This way it's easy to do lookups and we avoid duplicate data. This is generally considered a best practice.

Next to the entities state, we also have a queries state. This is also an object containing all the queries that have been requested. This is where we will store the id (or ids) relevant to the query.

Here's an example of what the state could look like:

{
  entities: {
    projects: {
      '708c8008-3455-49a9-b66a-5222bcadb0cc': {
        id: '708c8008-3455-49a9-b66a-5222bcadb0cc',
        title: 'Test project'
      },
       'e6538393-aa7e-4ec2-870b-f75b3d85f706': {
        id: 'e6538393-aa7e-4ec2-870b-f75b3d85f706',
        title: 'Test project2'
      }
    }
  }
  queries: {
    '{"domain":"projects","action":"list"}': {
      loading: false,
      ids: ['708c8008-3455-49a9-b66a-5222bcadb0cc', 'e6538393-aa7e-4ec2-870b-f75b3d85f706'],
      meta: {
        matches: 50
      }
    }
  }
}

Why use a normalized entities state?

By using a normalized state for entities, we can make sure that there's a single source of truth. This can be especially important when updating data. When we provide a way to do update requests using a new hook (hint, hint, useMutation), some existing state that can be shared between multiple queries will have to be updated.

Sideloading

See #12

To take advantage of sideloading, but retain our normalized entities state, we need to be able to combine the data when selecting it. This is implemented in the referenced PR above, but as @duivvv mentioned, being able to merge sideloaded data is something that is also needed in sdk-js.

As react-hooks-api is mostly a wrapper around sdk-js, it makes sense to create an exported plugin called merge in the sdk-js repo that can be used to select and merge the included data. See RFC sdk-js#31.

The only issue with this approach is the mapping between the singular form of an entity (company, which is included in the sideloading reference) and the plural form, or "domain" (companies), see the RFC for more context.

Returned data

Now how will we return the data? I personally don't see a use case (yet) to not return the data merged.

example hook

  const QUERY = () => ({
    domain: 'projects',
    action: 'list',
    options: {
      include: 'participant'
    }
  });

  const { loading, error, data } = useQuery(QUERY)

example data returned from the hook

[
  {
     id: '708c8008-3455-49a9-b66a-5222bcadb0cc',
     title: 'Test project'
     participant: {
        type: 'user',
        id: '82200479-576f-462c-ad38-aad52da23c55',
        lastName: 'Smith'
     }
  },
  {
     id: 'e6538393-aa7e-4ec2-870b-f75b3d85f706',
     title: 'Test project'
     participant: {
        type: 'user',
        id: '3defbb8a-c1db-465c-bc25-b36f48894e23',
        lastName: 'Wick'
     }
  }
]

So what do you guys think? Is this a good approach? Do you see any caveats that could come back and haunt us?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.