Giter VIP home page Giter VIP logo

rxdb-hooks's Introduction

rxdb-hooks

React hooks for integrating with RxDB

npm version downloads

Table of Contents

Click to expand

About

Nothing fancy, just conveniently handles common use cases such as:

  • subscribing to query observables and translating results into React state
  • cleaning up after subscriptions where necessary
  • paginating results
  • maintaining useful state information (i.e. data fetching or data exhaustion during pagination)
  • lazily creating or destroying collections

Installation

# using npm
npm install rxdb-hooks

# using yarn
yarn add rxdb-hooks

Example

Root.jsx:

import React, { useEffect } from 'react';
import { Provider } from 'rxdb-hooks';
import initialize from './initialize';

const Root = () => {
  const [db, setDb] = useState();

  useEffect(() => {
    // RxDB instantiation can be asynchronous
    initialize().then(setDb);
  }, []);

  // Until db becomes available, consumer hooks that
  // depend on it will still work, absorbing the delay
  // by setting their state to isFetching:true
  return (
    <Provider db={db}>
      <App />
    </Provider>
  );
};

Consumer.jsx:

import React from 'react';
import { useRxData } from 'rxdb-hooks';

const Consumer = () => {
  const { result: characters, isFetching } = useRxData(
    // the collection to be queried
    'characters',
    // a function returning the query to be applied
    collection =>
      collection.find({
        selector: {
          affiliation: 'jedi',
        },
      })
  );

  if (isFetching) {
    return 'loading characters...';
  }

  return (
    <ul>
      {characters.map((character, idx) => (
        <li key={idx}>{character.name}</li>
      ))}
    </ul>
  );
};

initialize.js:

const initialize = async () => {
  // create RxDB
  const db = await createRxDatabase({
    name: 'test_database',
  });

  // create a collection
  const collection = await db.addCollections({
    characters: {
      schema: {
        title: 'characters',
        version: 0,
        type: 'object',
        primaryKey: 'id',
        properties: {
          id: {
            type: 'string',
            maxLength: 100,
          },
          name: {
            type: 'string',
          },
        },
      },
    },
  });

  // maybe sync collection to a remote
  // ...

  return db;
};

Compatibility with RxDB

The core API of rxdb-hooks remains largely the same across all major versions beyond 1.x, however some parts of the internal implementation (most notably the plugin) differ based on the version of rxdb we need to target *. Please use the appropriate version of rxdb-hooks as per this table:

rxdb-hooks version targeted RxDB version
5.x 14.x
4.1.x 13.x
4.0.x 10.x, 11.x, 12.x
3.x 9.x
1.x, 2.x 8.x

* Versions 7.x of RxDB and below have not been tested and are not guaranteed to work with rxdb-hooks

Migration Guide

4.x => 5.x

  • useRxDocument has been dropped; for fetching single documents simply use useRxQuery or useRxData
  • observing lazily created collection has become an opt-in feature that, if needed, has to be explicitly enabled by using the provided plugin. For more info see Lazy instantiation of RxDatabase & RxCollections

API

Provider

The <Provider /> makes the RxDatabase instance available to nested components and is required for all subsequent hooks to work.

Props

Property Type Description
db RxDatabase the RxDatabase instance to consume data from

useRxDB

Returns the RxDatabase instance made available by the <Provider />

function useRxDB(): RxDatabase

Example

const db = useRxDB();

useRxCollection

Given a collection name returns an RxCollection instance, if found in RxDatabase.

function useRxCollection<T>(name: string): RxCollection<T> | null

Example

const collection = useRxCollection('characters');

useRxQuery

Subscribes to given RxQuery object providing query results and some helpful extra state variables.

function useRxQuery<T>(query: RxQuery, options?: UseRxQueryOptions): RxQueryResult<T>

options: UseRxQueryOptions

Option Type Description
pageSize number (optional) enables pagination & defines page limit
pagination "Traditional" | "Infinite" (optional) determines pagination mode:
Traditional: results are split into pages, starts by rendering the first page and total pageCount is returned, allowing for requesting results of any specific page.
Infinite: first page of results is rendered, allowing for gradually requesting more.
Default: "Traditional"
json boolean (optional) when true resulting documents will be converted to plain JavaScript objects; equivalent to manually calling .toJSON() on each RxDocument. Default: false

result: RxQueryResult<T>

Property Type Description
result T[] | RxDocument<T>[] the resulting array of objects or RxDocument instances, depending on json option
isFetching boolean fetching state indicator
currentPage number relevant in all pagination modes; holds number of current page
isExhausted boolean relevant in Infinite pagination; flags result list as "exhausted", meaning all documents have been already fetched
fetchMore () => void relevant in Infinite pagination; a function to be called by the consumer to request documents of the next page
resetList () => void relevant in Infinite pagination; a function to be called by the consumer to reset paginated results
pageCount number relevant in Traditional pagination; holds the total number of pages available
fetchPage (page: number) => void relevant in Traditional pagination; a function to be called by the consumer to request results of a specific page

Simple Example

const collection = useRxCollection('characters');

const query = collection.find().where('affiliation').equals('Jedi');

const { result } = useRxQuery(query);

Infinite Scroll Pagination Example

const collection = useRxCollection('characters');

const query = collection.find().where('affiliation').equals('Jedi');

const {
  result: characters,
  isFetching,
  fetchMore,
  isExhausted,
} = useRxQuery(query, {
  pageSize: 5,
  pagination: 'Infinite',
});

if (isFetching) {
  return 'Loading...';
}

return (
  <CharacterList>
    {characters.map((character, index) => (
      <Character character={character} key={index} />
    ))}
    {!isExhausted && <button onClick={fetchMore}>load more</button>}
  </CharacterList>
);

Traditional Pagination Example

const collection = useRxCollection('characters');

const query = collection.find({
  selector: {
    affiliation: 'Jedi',
  },
});

const {
  result: characters,
  isFetching,
  fetchPage,
  pageCount,
} = useRxQuery(query, {
  pageSize: 5,
  pagination: 'Traditional',
});

if (isFetching) {
  return 'Loading...';
}

// render results and leverage pageCount to render page navigation
return (
  <div>
    <CharacterList>
      {characters.map((character, index) => (
        <Character character={character} key={index} />
      ))}
    </CharacterList>
    <div>
      {Array(pageCount)
        .fill()
        .map((x, i) => (
          <button
            onClick={() => {
              fetchPage(i + 1);
            }}
          >
            page {i + 1}
          </button>
        ))}
    </div>
  </div>
);

useRxData

Convenience wrapper around useRxQuery that expects a collection name & a query constructor function

function useRxData<T>(
	collectionName: string,
	queryConstructor: ((collection: RxCollection<T>) => RxQuery<T> | undefined) | undefined,
	options?: UseRxQueryOptions
): RxQueryResult<T>

Example

const { result } = useRxData('characters', collection =>
  collection.find().where('affiliation').equals('Jedi')
);

Recipes

Query and Query Constructor memoization

By design, useRxQuery will re-subscribe to query object whenever it changes, allowing for query criteria to be modified during component updates. For this reason, to avoid unnecessary re-subscriptions, query should be memoized (i.e. via react's useMemo):

const { affiliation } = props;
const collection = useRxCollection('characters');

const query = useMemo(
  () =>
    collection.find({
      selector: {
        affiliation,
      },
    }),
  [collection, affiliation]
);

const { result } = useRxQuery(query);

Same goes for useRxData and the queryConstructor function:

const { affiliation } = props;

const queryConstructor = useCallback(
  collection =>
    collection.find({
      selector: {
        affiliation,
      },
    }),
  [affiliation]
);

const { result } = useRxData('characters', queryConstructor);

Lazy instantiation of RxDatabase & RxCollections

All rxdb-hooks give you the ability to lazily instantiate the database and the collections within it. Initial delay until the above become available is absorbed by indicating the state as fetching (isFetching:true).

Since v5.0.0 of rxdb-hooks, observing newly created collections has become an opt-in feature that, if needed, has to be enabled via the provided observeNewCollections plugin:

import { addRxPlugin } from 'rxdb';
import { observeNewCollections } from 'rxdb-hooks';

addRxPlugin(observeNewCollections);

Adding the plugin makes it possible for all rxdb-hooks to pick up data from collections that are lazily added after the inital db initialization.

Also note that lazily instantiating the rxdb instance itself is supported out-of-the-box, the plugin only affects lazy collection creation.

Mutations

Performing mutations on data is possible through the APIs provided by RxDocument and RxCollection:

Example

const collection = useRxCollection('characters');

collection.upsert({
  name: 'Luke Skywalker',
  affiliation: 'Jedi',
});

LICENSE

MIT

rxdb-hooks's People

Contributors

cvara avatar dependabot[bot] avatar plmercereau avatar samyok avatar

Stargazers

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

Watchers

 avatar  avatar  avatar

rxdb-hooks's Issues

Wrong paths in package.json

Hi Christoforos 🤝

I'm not sure, but it seems like something went wrong with the build. package.json contains following entries:

	"version": "3.0.0",
[...]
	"main": "./dist/index.js",
	"types": "./dist/index.d.ts",

but files are under dist/src:

$ find -L packages/frontend/node_modules/rxdb-hooks -name "index.*"
packages/frontend/node_modules/rxdb-hooks/dist/src/index.js
packages/frontend/node_modules/rxdb-hooks/dist/src/index.d.ts
packages/frontend/node_modules/rxdb-hooks/src/index.ts

Notice also the last entry. I think it shouldn't be here.

Database type doesn't match type expected by Provider

I'm just getting started with RxDB and have run into a very similar issue to #14. Given how much RxDB and its TypeScript support has changed since then, I can't say for certain that they're the same issue. If they are, please feel free to merge the issues.

Following the RxDB TypeScript docs, the createRxDatabase call will return a typed instance of a specific database (e.g., MyDatabase in the linked page). This type is not equivalent to RxDatabase and as such, can't be supplied as the db prop on rxdb-hook's Provider. Instead, you get a type error like:

Type 'MyDatabase' is not assignable to type 'RxDatabase<CollectionsOfDatabase, any, any> | undefined'.

I've worked around it locally by just ignoring the type:

<Provider db={db as any}>{props.children}</Provider>

That's enough to get most of the hooks working. However, the useRxDB hook will not return a reference typed as MyDatabase, so you can't do much with the reference without type casting.

useRxData doesn't support findByIds

I'm trying to query for a set of IDs with a query supplied to useRxData. Unfortunately, it doesn't seem to work. The type definitions don't appear to be compatible, as findByIds returns a Map<string, doc_type>. Thinking maybe the type definitions just needed to be updated, I typed the query constructor instance as any, but that didn't help. The query never resolves and isFetching is always true.

useRxData doesn't support findOne

I've run into a type definition error when providing useRxData with a query constructor that uses findOne. I think the issue is that findOne can return null, while find always returns a value, even if that value is an empty array. The TypeScript error isn't the clearest thing in the world:

TS2769: No overload matches this call.
  Overload 1 of 3, '(collectionName: string, queryConstructor: QueryConstructor<TodoChainDoc> | undefined): RxQueryResultDoc<TodoChainDoc>', gave the following error.
    Argument of type '(collection: RxCollection<TodoChainDoc>) => RxQuery<TodoChainDoc, RxDocument<TodoChainDoc, {}> | null>' is not assignable to parameter of type 'QueryConstructor<TodoChainDoc>'.
      Type 'RxQuery<TodoChainDoc, RxDocument<TodoChainDoc, {}> | null>' is not assignable to type 'RxQuery<TodoChainDoc, RxDocument<TodoChainDoc, {}>> | RxQuery<TodoChainDoc, RxDocument<TodoChainDoc, {}>[]> | undefined'.
        Type 'RxQuery<TodoChainDoc, RxDocument<TodoChainDoc, {}> | null>' is not assignable to type 'RxQuery<TodoChainDoc, RxDocument<TodoChainDoc, {}>>'.
          The types of '$.value' are incompatible between these types.
            Type 'RxDocument<TodoChainDoc, {}> | null' is not assignable to type 'RxDocument<TodoChainDoc, {}>'.
              Type 'null' is not assignable to type 'RxDocument<TodoChainDoc, {}>'.
  Overload 2 of 3, '(collectionName: string, queryConstructor: QueryConstructor<TodoChainDoc> | undefined, options?: Override<UseRxQueryOptions, { ...; }> | undefined): RxQueryResultDoc<...>', gave the following error.
    Argument of type '(collection: RxCollection<TodoChainDoc>) => RxQuery<TodoChainDoc, RxDocument<TodoChainDoc, {}> | null>' is not assignable to parameter of type 'QueryConstructor<TodoChainDoc>'.
  Overload 3 of 3, '(collectionName: string, queryConstructor: QueryConstructor<TodoChainDoc> | undefined, options?: Override<UseRxQueryOptions, { ...; }> | undefined): RxQueryResultJSON<...>', gave the following error.
    Argument of type '(collection: RxCollection<TodoChainDoc>) => RxQuery<TodoChainDoc, RxDocument<TodoChainDoc, {}> | null>' is not assignable to parameter of type 'QueryConstructor<TodoChainDoc>'.

I can manually query against the collection or just use find and unwrap the array in the meanwhile. Please let me know if I can be of any assistance. I couldn't see a simple way to change the return type based on using find vs findOne and I don't want to break code on existing users by forcing null as a potential return value on all queries. Maybe the solution is a new hook (e.g, useRxDataOne)?

useRxData collection filtering briefly malfunctions

I'm trying to load data belonging to some user like this:

useRxData<Stuff>(
        'stuff',
        (collection) => collection.find().where('user_id').equals(user?.id),
);

This works, but there's a brief moment where it loads everything regardless of user_id. I can't fix it by using row level security, because those other rows are intended to be public, just displayed elsewhere. They flash for a moment, then disappear again. If I console.log the retrieved dcouments, you can see the hook first returns 0 (before fetching), then 11 (with isFetching set to false), then 11 with isFetching set to true, then 2, then 11, then 2 again. 2 is the number of elements after filtering.

image

useRxCollection returns null the first time it is called?

Hello and thanks for the awesome project!

While using useRxCollection I found it doesn't return the collection the first time it is called in a particular component for me. Is this by design?

ex:

const itemsCollection = useRxCollection('items')
 // ❓ useRxCollection returns null the first time????
  console.log('itemsCollection', itemsCollection)
const query = itemsCollection.find().where('owner').equals(userId)
const { result: items, isFetching: isFetchingItems } = useRxQuery(query)

I was expecting itemsCollection to get the right owner but it throws an error because the collection is null on the first render of the component. I made sure I did the setup with the provider correctly and used await on db.addCollections({ items: {...}}).

I might be messing up somewhere else but figured I could open here to see if anyone else has run into this.

types for database?

I'm trying to figure out how to get the types to work in the provider. I currently have the following when creating my db where DatabaseCollections is the types I've setup for my db:

const [db, setDb] = React.useState<RxDatabase<DatabaseCollections>>()

...

const db = await createRxDatabase<DatabaseCollections>(…)

…

<Provider db={db}>{…}</Provider>

However I get the following type error on the Provider component:

Type 'RxDatabase<DatabaseCollections>' is not assignable to type 'RxDatabase<CollectionsOfDatabase>'.

How to handle multiple databases?

Hello,
Assuming I have two databases, and would like to access either through useRxDB, how would I go about it, knowing the Provider component only takes one instance of RxDB?
Thank you.

Electron remote breaks hooks

Hello,
In an Electron project I am creating the RXDB database through Electron's remote. My use case includes having multiple windows, so ideally, I'd start the DB on the main process and expose it to my renderer process, instead of starting a new database process for each window (leaderElection does not seems to work when it comes to multiple Electron windows, so that's off the table).

However, passing the DB object from main to renderer process seems to break this package. I can still interact with the database normally. It's just that all hooks from rxdb-hooks fail silently.

I have created a small sample project to demonstrate this.
Any insight would be most helpful.
Thank you very much for your time.

useRxData and component re-render

Hi,
I'm fetching paginate results in a component with the following code and using https://github.com/welldone-software/why-did-you-render to monitor re-renders:

  const queryConstructor = (collection: any) => {
    return collection.find().sort({ created_at: 'desc' });
  };


  const {
    result: videos,
    isFetching,
    fetchMore,
    isExhausted,
    resetList,
    currentPage,
  } = useRxData<VideoDocType>('videos', queryConstructor, {
    pageSize: 5,
    pagination: 'Infinite',
  });

This is the only hook I've in the code.

I've noticed this warning:

image

is this expected?

useRxCollection does not support lazy collection initialization

Hello,
First of all, a big thanks for this awesome library!

I am loading collections after DB creation with db.addCollections. The problem (I think) is the collection is not created yet when the useRxCollection hook is called.
As a result, the above code:

  const { isFetching, result } = useRxData(
    name,
    (collection) => collection.find()
  )

ends up with isFetching being false, and

const collection = useRxCollection(name)

would also send an error if the collection is not created yet.
Is there a way to make rxdb-hooks work in this use case?
Many thanks in advance!

Question: useRXCollection not able to notice deletion and recreation of collection in one sitting

Hello, i am currenlty facing an issue where users of my app are logging in and out right after eachother. while logging out im removing some user specific collections, which leads to the replicationstate of collections beeing reset in the rxdb itself. so far so good.

but now it happen that users login right after again, and the old references to useRXCollections are now destroyed:true, as one can expect.

Im recreating the collections properly before the user can login again, but this is not picked up by rxdb-hooks anymore as if the collection has been found immidiatley there is no subscription to the "newCollection$" subject:

useEffect(() => {
		if (!db) {
			return;
		}
		const found = db[name];
		if (found) {
			setCollection(found); <------ here we wont subscribe
		} else {
			const sub = db.newCollections$.subscribe(col => {
				if (col[name]) {
					// We don't unsubscribe so that we get notified
					// and update collection if it gets deleted/recreated
					setCollection(col[name]);
				}
			});
			return () => {
				sub.unsubscribe();
			};
		}
	}, [db, name]);

i am now wondering why this is the behaviour rxdb-hooks opt for, and if i get side effects im not aware of if i subscribe to the subject anyhow. Or ist this just a usecase that has not been tought of and therfore is not covered?

Better typescript support

rxdb-hooks are super useful, but they miss the type of support I am looking for right now. Also this library seems a little dormant, as last commit was over a year ago, so a proper update of dependencies might be nice.

Issues

In the limited time I have been trying to use this library with full typescript support I encountered one issue:

  • The main issue is that using .findOne() still returns a type of array, even though the actual value is not an array.

Improvements

  • Add support for rxdb 15 and typescript 5
  • Add a hookBuilder<Collections>() function, that returns all of the hooks, but fully typed, so that you can only specify actual collections and the results are automatically typed.

I am willing to open a pull request and implement these changes (if I am able to get them to work), but I first wanted to get your opinion.

Should I try to get this working and open a pull request?

useRxCollection returns null in "Simple Example" scenario

Hey, I'm trying to use rxdb-hooks,
I really like the idea.

Inside my component i'm using this as follows:

const db = useRxDB(); // Works as expected returning a DB that contains the collection named 'contacts'
const collection = useRxCollection<Contact>('contacts'); // returns null at first
const query = collection.find().where('phoneNumber').equals('5555555'); // we need the collection to create a query
const { result: contacts, isFetching } = useRxQuery<Contact>(query); // We need the query in order use this hook, cannot be conditional

Thank you.

Is RXDB v12 supported?

Hi,
Been using with RXDB V11 & rxdb-hooks with no problems. However, noticed that a major RXDB version 12 has been released. Wondering, whether is supported by rxdb-hooks?

Based on README, it seems not yet?
2022-06-08_13-48

hooks stuck loading on local but work on production

Screenshot 2023-02-16 at 12 17 06

See repo to reproduce: https://github.com/idesignpixels/rxdb-hooks-issue
run npm install & npm start

isFetching is always true on local.

I've tried with [email protected], [email protected] and [email protected]

code using hook:

function App() {
  const { result: characters, isFetching } = useRxData(
    // the collection to be queried
    'characters',
    // a function returning the query to be applied
    collection =>
      collection.find({
        selector: {
          affiliation: 'jedi',
        },
      })
  );

  if (isFetching) {
    return 'loading characters...';
  }

  return (
    <div className="App">
        <ul>
        {characters.map((character, idx) => (
          <li key={idx}>{character.name}</li>
        ))}
      </ul>
    </div>
  );
}

useRxData doesn't return result and keeps fetching

When using rxdb-hooks version 5.0.1 with rxdb 14.1.2 the useRxData hook doesn't return any result but stays stuck in the isFetching: true state.

Our implementation uses Dexie as a storage engine. We also have a separate build using SQLite, which does work. Which indicates the query we're using seems to work. Using useCollection and manually querying the collection also returns the correct results.

Working example with Dexie:

const collection = useRxCollection<Submission>("submissions");

  useEffect(() => {
    collection
      ?.find()
      .exec()
      .then((results) => console.log(results));
  }, [collection]);

This doesn't work with Dexie:

const { result, isFetching } = useRxData<Submission>("submissions", (collection) =>
    collection.find()
  );

Both examples work with SQLite.

Do you have any idea what could be causing this issue?

New functionality: collection.count

I would love to see support for collection.count queries in rxdb-hooks. Do you think this would best work as a useRxCount hook or as part of the useRxData hook?

If you could offer your feedback and approve of a direction then I would be happy to try to implement this. I don't assume that the maintainers have time to implement every feature request.

collection.remove$ Does not seem to be observable

I am working with data that is partitioned on the backend, and the client RxDB instance will only ever have data from one partition at a time. Different partitions are accessed via different directories in the HTTP Replication URL, so I'll have a process similar to this each time the client needs to switch partitions:

  • Observe the removal of a collection's records, like:
    collection.remove$.subscribe( r => console.error('Remove Log:', r) );
  • Update the HTTP Replication endpoint to point to the new partition
  • Call collection.reSync() to get the new data

However, I'm noticing that nothing is logged when I use window.collection.remove() from the browser console. Am I misunderstanding how the observable works?

Thanks

TypeScript + useRxCollection() + static methods not working?

Hey there!

I've got a collection that looks like this:

type EventCollection = RxCollection<
  EventRecordType,
  Record<string, never>,
  EventCollectionStaticMethods
>;

It has some static methods, but if I call useRxCollection(), there's no good way of TypeScript knowing that. The hook only accepts a single generic which is for the document type (i.e. RxCollection<T>), so I can't provide the types for my static methods.

I think it would make more sense if the generic was for the collection itself, rather than the document type, e.g.:

const events = useRxCollection<EventCollection>("events")

I realize that's a breaking change, though, so perhaps it would be enough for the function to accept all three generic types? That way, I could at least do this:

declare function useRxCollection<A, B, C>(
  name: string,
): RxCollection<A, B, C> | null;

...

const events: EventCollection = useRxCollection("events")

Right now, that line of code fails because the second and third generics aren't being passed through.

I'm happy to open a PR if you want, though I think the change would be very quick.

Thanks!

How to combine multiple collection queries into a single hook?

HI All,

This might be more of a react question and not as related to the hooks, I'm just struggling to understand how I can combine multiple collection queries into a single hook result that gets updated if the data in one query changes in the database?

I want to re-use the logic provided in these hooks because it is so robust, and gather data from two queries to construct data for my UI in a single hook that can be placed in my components.

I've been poking my way through trying to create a custom hook that implements multiple of these but I'm not having much luck.

Would anyone happen to have any sample code or insight into how I can achieve this using these hooks without having to reimplement all the 'isFetching' and observables?

Is useMemo what I should be looking at?

Any insight is greatly appreciated

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.