use-oop-swr

npm install --save use-oop-swr

Usage no npm install needed!

<script type="module">
  import useOopSwr from 'https://cdn.skypack.dev/use-oop-swr';
</script>

README

use-oop-swr

OOP useSWR hook wrapper

NPM JavaScript Style Guide Badges Badges Badges Badges Badges Badges

Install

1. Install package

npm install --save use-oop-swr
yarn add use-oop-swr

2. Install class-transformer and reflect-metadata

  1. class-transformer installation

    npm install class-transformer --save
    
    yarn add class-transformer
    
  2. reflect-metadata shim is required, install it too:

    npm install reflect-metadata --save
    
    yarn add reflect-metadata
    

    add to the top of index.tsx

    import 'reflect-metadata';
    

    or add to <script> reflect-metadata in the head of your index.html:

    <html>
      <head>
        <!-- ... -->
        <script src="node_modules/reflect-metadata/Reflect.js"></script>
      </head>
      <!-- ... -->
    </html>
    

Usage

The aim of this package is to end up with annoying practice of adding properties to data received from api with swr.

In JavaScript there are two types of objects

plain (literal) objects class (constructor) objects Plain objects are objects that are instances of Object class. Sometimes they are called literal objects, when created via {} notation. Class objects are instances of classes with own defined constructor, properties and methods. Usually you define them via class notation.

So, what is the problem?

Sometimes you want to transform plain javascript object to the ES6 classes you have. For example, if you are loading a json from your backend, some api or from a json file, and after you JSON.parse it you have a plain javascript object, not instance of class you have.

For example you have a list of users in your users.json that you are loading:

[
  {
    "id": 1,
    "firstName": "Johny",
    "lastName": "Cage",
    "age": 27
  },
  {
    "id": 2,
    "firstName": "Ismoil",
    "lastName": "Somoni",
    "age": 50
  },
  {
    "id": 3,
    "firstName": "Luke",
    "lastName": "Dacascos",
    "age": 12
  }
]

And you have a User class:

export class User {
  id: number;
  firstName: string;
  lastName: string;
  age: number;

  getName() {
    return this.firstName + ' ' + this.lastName;
  }

  isAdult() {
    return this.age > 36 && this.age < 60;
  }
}

You are assuming that you are downloading users of type User with swr and may want to write following code:

import * as React from 'react';
import axios from 'axios';
import useSWR from 'swr';
import { User } from './User';

export type UsersProps = {};

export const Users: React.FC<UsersProps> = (props) => {
  const { data } = useSWR<User[]>('yourapiendpoint/users', (url) =>
    axios.get(url).then((res) => res.data)
  );

  return <div>{JSON.stringify(data)}</div>;
};

In this code you can use users[0].id, you can also use users[0].firstName and users[0].lastName. However you cannot use users[0].getName() or users[0].isAdult() because "users" actually is array of plain javascript objects, not instances of User object. You actually lied to compiler when you said that its users: User[].

So what to do? How to make a users array of instances of User objects instead of plain javascript objects? Solution is to create new instances of User object and manually copy all properties to new objects. But things may go wrong very fast once you have a more complex object hierarchy.

Alternatives? Yes, you can use use-oop-swr. Purpose of this library is to help you to map your plain javascript objects to the instances of classes you have.

This library also great for models exposed in your APIs, because it provides a great tooling to control what your models are exposing in your API. Here is an example how it will look like:

import * as React from 'react';
import { useOOPSWR } from 'use-oop-swr';
import axios from 'axios';
import useSWR from 'swr';
import { User } from './User';

export type UsersProps = {};

export const Users: React.FC<UsersProps> = (props) => {
  const [data, swrData] = useOOPSWR(
    User, // <--- Cool!
    useSWR('yourapiendpoint/users', (url) =>
      axios.get(url).then((res) => res.data)
    )
  );

  return <div>{JSON.stringify(data)}</div>;
};

Now you can use users[0].getName() and users[0].isAdult() methods.

Arguments

  • classInstance: InstanceType: Class instance of needly data
  • swrData:? SWRResponse: SWR Response object. Docs
  • options:? ClassTransformOptions: Options of class-transform plainToInstance function. Docs

Returns

Hooks returns array with two items. First class instance with, second one is data from swr hook

Inspired by

License

MIT © kolengri