Git Product home page Git Product logo

use-pouchdb's Introduction

usePouchDB

semantic-release Known Vulnerabilities npm

React Hooks for PouchDB.

Overview

usePouchDB is a collection of React Hooks to access data in a PouchDB database from React components.

The goal of usePouchDB is to ease the use of PouchDB with React. Enabling developers to create offline first apps.

Quick-start

You can find the Getting Started docs here (or on GitHub).

These docs walk you through setting up PouchDB and usePouchDB. They give you also a quick introduction to PouchDB and Apache CouchDB. But PouchDB's Guides are recommended to learn PouchDB.

You can find a introduction to React here.

If you know what you're doing and only want to quick start, read on...

Installation

usePouchDB requires React 16.8.3 or later.

npm install use-pouchdb
# or
yarn add use-pouchdb

You'll also need to install PouchDB. There is also a special browser version:

npm install pouchdb-browser
# or
yarn add pouchdb-browser

To use the useView hook pouchdb-mapreduce must be installed and setup. If you use the pouchdb or pouchdb-browser packages, it is already setup.

npm install pouchdb-mapreduce
# or
yarn add pouchdb-mapreduce

For using the useFind hook pouchdb-find must be installed and setup.

npm install pouchdb-find
# or
yarn add pouchdb-find

Bind usePouchDB

usePouchDB exports a <Provider /> to make one or multiple PouchDB databases available to its components sub-tree.

import React from 'react'
import ReactDOM from 'react-dom'
import PouchDB from 'pouchdb-browser'

import { Provider } from 'use-pouchdb'

import App from './App'

const db = new PouchDB('local')

ReactDOM.render(
  <Provider pouchdb={db}>
    <App />
  </Provider>,
  document.getElementById('root')
)

Hooks

All hooks are listed here.

  • usePouch - Access the database provided by <Provider />.
  • useDoc - Access a single document and subscribe to its changes. The hook version of db.get.
  • useAllDocs - Load multiple documents and subscribe to their changes. Or a range of docs by their ids. The hook version of db.allDocs.
  • useFind - Access a mango index and subscribe to it. Optionally create the index, if it doesn't exist. The hook version of db.createIndex and db.find combined.
  • useView - Access a view and subscribe to its changes. The hook version of db.query.

Example

Load a single document and display it. useDoc is the hook version of db.get, but it also subscribes to updates of that document and automatically loads the new version.

import React from 'react'
import { useDoc } from 'use-pouchdb'

export default function Post({ postId }) {
  const { doc, loading, error } = useDoc(postId)

  if (error && !loading) {
    return <div>something went wrong: {error.name}</div>
  }

  if (doc == null && loading) {
    return null
  }

  return (
    <article>
      <div>
        <h3>{doc.author}</h3>
        <p>{doc.text}</p>
      </div>
    </article>
  )
}

Changelog

usePouchDB follows semantic versioning. To see a changelog with all usePouchDB releases, check out the Github releases page.

Contributing

Contributions in all forms are welcomed. โ™ก

If you have questions, Contributing.md might answer your questions.

To create a welcoming project to all, this project uses and enforces a Code of Conduct.

use-pouchdb's People

Contributors

dependabot[bot] avatar firede avatar snyk-bot avatar terreii 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

Watchers

 avatar  avatar  avatar  avatar

use-pouchdb's Issues

`useAllDocs` not subscribing to updates

Description

I'm using your todo example and although the todo-list is shown on the page and new todos are added using the form, the new todo won't be shown until I reload the page.

Steps to Reproduce

  1. Install dependencies
npm i pouchdb-browser use-pouchdb pouchdb-node express-pouchdb
  1. Create src/AddTodo.js:
import { usePouch } from "use-pouchdb";

export default function AddTodo() {
  const db = usePouch();

  const [input, setInput] = React.useState("");

  const handleAddTodo = async (event) => {
    event.preventDefault();

    const doc = {
      _id: new Date().toJSON(),
      type: "todo",
      text: input,
      done: false
    };

    await db.put(doc);

    setInput("");
  };

  return (
    <form onSubmit={handleAddTodo}>
      <input
        type="text"
        value={input}
        minLength={1}
        onChange={(event) => {
          setInput(event.target.value);
        }}
      />

      <button>Add Todo</button>
    </form>
  );
}
  1. Create src/TodoList.js
import React from "react";
import { useAllDocs } from "use-pouchdb";
const Todo = ({ todo }) => {
  return (
    <li className="todo-item">
      <span className="todo-item__text">{todo.text}</span>
    </li>
  );
};

export default function TodoList() {
  const { rows: todos, loading } = useAllDocs({
    include_docs: true
  });

  return (
    <ul className="todo-list">
      {(todos && todos.length) || loading
        ? todos.map((todo) => <Todo key={todo.key} todo={todo.doc} />)
        : "No todos, yay!"}
    </ul>
  );
}
  1. Modify App.js so it uses TodoList and AddTodo and also the Provider:
import "./styles.css";
import React, { useEffect } from "react";
import PouchDB from "pouchdb-browser";
import { Provider } from "use-pouchdb";
import AddTodo from "./AddTodo";
import TodoList from "./TodoList";

export default function App() {
  const [db, setDB] = React.useState(() => new PouchDB("local"));

  useEffect(() => {
    const listener = (dbName) => {
      if (dbName === "local") {
        setDB(new PouchDB("local"));
      }
    };

    PouchDB.on("destroyed", listener);

    return () => {
      PouchDB.removeListener("destroyed", listener);
    };
  }, []);

  return (
    <Provider pouchdb={db}>
      <div className="App">
        <AddTodo />
        <TodoList />
      </div>
    </Provider>
  );
}
  1. Create src/setupProxy.js:
// The node version of PouchDB (without browser stuff)
const PouchDB = require("pouchdb-node");
const expressPouchDB = require("express-pouchdb");

const PrefixedPouch = PouchDB.defaults({
  prefix: "db/" // All PouchDB data will be stored in the directory ./db/*
});

module.exports = function (app) {
  // app is the Create-React-App dev server.
  // Our databases will be available at http://localhost:3000/db/*
  app.use("/db", expressPouchDB(PrefixedPouch));
};

  1. Run the server
npm start
  1. In the browser, type something in the form
  2. Click "Add Todo" or hit enter.
  3. Notice that the todo isn't shown in the page and therefore, useAllDocs isn't subscribed to updates.
  4. Check IndexedDB in dev tools to see that the todo has been successfully added.
  5. Reload to see it get's added to the page after reload.

Here's the codesandbox just in case.

Expected Behavior

Todo Item is expected to appear in the browser without reloading the page(useAllDocs being subscribed to updates)

Your Environment

use-pouchdb version 1.3.3
pouchdb-browser version 7.3.0
express-pouchdb 4.2.0
pouchdb-node 7.3.0

  • CouchDB version used: no CouchDB server, everything offline.
  • PouchDB version used: no PouchDB server
  • React version used: 18.0.0
  • Browser name and version: Chrome 101.0.4951.64 (Official Build) (arm64)
  • Operating system and version: macOS Big Sur 11.2.2

Additional Context

Thanks in advance for any help you're able to provide.

subscribed view (useView) does not re-run after doc delete while reducing

Description

Adding and updating docs re-runs a saved view as expected and runs map and reduce (_sum) properly. Deleting docs does not re-run the view as expected and results in incorrect _sum calculation (no update).

Steps to Reproduce

Delete doc from a saved view while reducing.

Expected Behavior

subscribed view should re-run after deleting document related to a subscribed view.

Your Environment

  • CouchDB version used:
  • 3.1.1
  • PouchDB version used:
  • 7.2.2
  • React version used:
  • 17.0.1
  • Browser name and version:
  • Firefox / ios / safari
  • Operating system and version:
  • Macos

Additional Context

jest generates error: Cannot find module 'use-pouchdb'

Description

We started using use-pouchdb in one of our projects.
It actually works very well. The connection to the database was quick and easy.
But for some reason the execution of the tests is not possible anymore.
As soon as a component is to be rendered that has an import from use-pouchdb, the following error is generated:

Cannot find module 'use-pouchdb' from '<path-to-component>.js'.

No component from use-pouchdb is used, only the import is available.
To isolate the error, I created a new project via npx create-react-app. Here I can recreate the error in the same way, so that I would exclude side effects from other dependencies in my project.

Steps to Reproduce

  • npx create-react-app my-app
  • cd ./my-app
  • npm i use-pouchdb
  • Modify App.test.js: Add to imports: import { Provider } from "use-pouchdb";
  • npm run test

Expected Behavior

Test should succeed.

Your Environment

  • package.json

    {
      "name": "my-app",
      "version": "0.1.0",
      "private": true,
      "dependencies": {
        "@testing-library/jest-dom": "^4.2.4",
        "@testing-library/react": "^9.5.0",
        "@testing-library/user-event": "^7.2.1",
        "react": "^16.13.1",
        "react-dom": "^16.13.1",
        "react-scripts": "3.4.3",
        "use-pouchdb": "^1.2.0"
      },
      "scripts": {
        "start": "react-scripts start",
        "build": "react-scripts build",
        "test": "react-scripts test",
        "eject": "react-scripts eject"
      },
      "eslintConfig": {
        "extends": "react-app"
      },
      "browserslist": {
        "production": [
          ">0.2%",
          "not dead",
          "not op_mini all"
        ],
        "development": [
          "last 1 chrome version",
          "last 1 firefox version",
          "last 1 safari version"
        ]
      }
    }
  • App.test.js

     import React from 'react';
     import { render } from '@testing-library/react';
     import App from './App';
     import { Provider } from "use-pouchdb";
    
     test('renders learn react link', () => {
       const { getByText } = render(
       <App />);
       const linkElement = getByText(/learn react/i);
       expect(linkElement).toBeInTheDocument();
     });
  • Operating system and version: Windows 10 Pro, 64 Bit

Rename useQuery to useView

Summary

Query is more a single fetch. But Views are the underlying construct. Similarly to useDoc, useQuery should reflect what you tap into. It should be renamed into useView.

Desired Behavior

No change in behavior, just a rename.

Semantic Release and Travis

Summary

Releases should be tested and automatically published.

Desired Behavior

Every pull request should be tested and published once it got merged.

Possible Solution

Travis could be used for tests.
And Semantic-Release for automatically publishing.

Additional context

Semantic-Release should only be activated after the first release.

Check list

  • Travis
  • Semantic-Release

Optimize for many subscriptions

Summary

In the first version every hook subscribe for its own updates. Creating a HTTP request for each.
This can be optimized.

Desired Behavior

Only use one "all documents" change-feed and only one filtered change for each view.

Possible Solution

There should be a subscription manager.
It should optimize the number of active subscriptions.

Additional context

There will be a warning, if for every view and every document a new subscription is created.
Also every change feed subscription creates a new HTTP request!

Getting TypeError: set is not iterable when updating documents

Description

I have a react page connecting with a "useDoc" hook getting a single document. It brings this document up for editing, and then after updates are made and the user clicks on a button to update, I get an error like this:

    at notify (subscription.js:171:1)
    at subscription.js:157:1

The useDoc hook has no parameters other than the document ID.
Updates to the document are done with a generic document update hook based on the example documentation on the web page.

Here is the code for the update command:

  const db = usePouch();
  return useCallback(
    async (updatedDoc: any) => {
          let curDateStr=(new Date()).toISOString()
          updatedDoc.updatedAt = curDateStr;
          let response: PouchResponse = cloneDeep(PouchResponseInit);
          try { response.pouchData = await db.put(updatedDoc); }
          catch(err) { response.successful = false; response.fullError = err;}
          if (!response.pouchData.ok) { response.successful = false;}
      return response
    },[db])
}

This update hook works fine and throws no errors unless called by a page with useDoc().

If I change the useDoc() hook to just code using db.get, I don't get an error either, but I'm also not subscribed to updates and won't see them if the page changes. Was hoping to keep that functionality because this is for a distributed app where other users could make changes on their own copies which replicate back to this one, and I'd rather have the screen refresh with those updates when they happen.

Also, although I get this error message, the data does seem to update properly and flow upstream to replicas as well.

Steps to Reproduce

My app has a lot more code, but I believe it can be reproduced by:

  • Creating a React component that uses useDoc() hook
  • Display data on page
  • Have button to update. When update, either use db.put directly or through custom hook

Expected Behavior

No error

Your Environment

  • CouchDB version used: 3.2.2
  • PouchDB version used: 7.3.1
  • React version used: 18.2
  • Browser name and version: Chrome, Safari
  • Operating system and version: Mac OS

Add support for multiple DBs

Summary

It is not uncommon to use multiple DB. Often the local db and the remote db.
It would be a good idea to have access to multiple DBs contexts with usePouchDB.

Desired Behavior

Every hook should have an additional optional option to specify the db to use. If this option is omitted, then the closest DB in the component-tree should be used (the default).

Possible Solution

The context Provider should check if there is already an context. And if it exists, then include all its DBs into its context, and overwrite the default one.
The DBs can then be selected using their names.

Additional context

This would allow many new use-cases:

  • Have a local db and a remote db. The local is used the most. But the remote can be accessed by the log-in-component.
  • Start with using a remote db. Once the local db did sync and all views are indexed, switch to the local db.
  • Use a temporary db (in memory only). To check out the app. And once the user signs up, then create a local and remote db and sync the temp to them.

Add a useAllDocs hook

Summary

useAllDocs should be a hook that give access to db.allDocs.

Desired Behavior

It should accept most options of db.allDocs and also return it's result.
Additionally it should also subscribe to updates of the section and update its result.

Possible Solution

Use the new SubscriptionManager and enhance it, if needed.

Additional context

db.allDocs is really powerful and has bonus, that it doesn't need the creation of a secondary index.

Implement useFind

Summary

useFind should be a hook that give access to db.find.

Desired Behavior

It should accept most options of db.find and also return it's result.
Additionally it should also subscribe to updates of the view and re-query when they occur.

Possible Solution

Use filtered-changes for updates to the mango-query.

Additional context

This first version can be only optimized local DB.

Implement useQuery

Summary

useQuery should be a hook that give access to db.query.

Desired Behavior

It should accept most options of db.query and also return it's result.
Additionally it should also subscribe to updates of the view and re-query when they occur.

Possible Solution

Use filtered-changes for updates to the view.

Additional context

This first version can be only optimized local DB.

useFind with sort return error 'no_usable_index'

Using useFind hook for getting sorted data.

Description

Im trying to get some data from my pouch (local, synced with remote couch), sorted by index number.
My data is like the following:

{
  "_id": "extendedField#Financiadora#96dd868704c9efb218b0c98fa701d106:612C04170D87B5C76B4C480A107B621C",
  "_rev": "2-f66bc8ab831e80f842f3b2fc746a8c38",
  "entidad": "Financiadora",
  "label": "Nombre del contacto",
  "permiso": "edit_basic",
  "step": 1,
  "index": 2,
  "org": "96dd868704c9efb218b0c98fa701d106",
  "app": "alfred",
  "model": "extendedFields"
}

My code to get the data:

const { docs: entityFields, error: efError } = useFind({
        // Create and query an index for all extended fields
        index: {
            fields: ['model', 'app', 'org', 'entidad', 'index'],
        },
        selector: {
            model: 'extendedFields',
            app: 'alfred',
            org: `${editData?.org}`,
            entidad: `${editData?.nombreEntidad}`,
            index: { $gt: 0 },
        },
       sort: [{ index: 'asc' }],
        db: 'alfred',
    })

I got the error:
{error: 'no_usable_index', message: 'There is no index available for this selector.'}

I see the index was there in the pouchdb-debug log

Steps to Reproduce

Just use the useFind hook in a react component, of course having some sample data like the provided one.

Expected Behavior

I expected to get the data sorted by index number.

Your Environment

This are the related installed packages:

"pouchdb": "^7.2.2",
"pouchdb-debug": "^7.2.1",
"pouchdb-find": "^7.2.2",
"use-pouchdb": "^1.3.0",
 "react": "^17.0.1",

Browser: Firefox 91.0.2 (64-bit)
Operating System: macos BigSur [ 11.2.1 (20D75) ]

Additional Context

Using just puchdb-find with create index just works as expected.

localDb
        ?.createIndex({
            index: { fields: ['model', 'app', 'org', 'entidad', 'index'] },
        })
        .then(() => {
            return localDb.find({
                selector: {
                    model: 'extendedFields',
                    app: 'alfred',
                    org: `${editData?.org}`,
                    entidad: `${editData?.nombreEntidad}`,
                    index: { $gt: -1 },
                },
                sort: [{ index: 'asc' }],
            })
        })
        .then((res) => {
            // console.log('FIELDS :', res.docs)
            setEntityFields(res.docs)
        })
        .catch((e) => {
            console.log('<<<<ERROR CREATE QUERY INDEX>>>>>:', e)
        })

db.type() is deprecated

Description

Basically I started having this warning on my console:
db.type() is deprecated and will be removed in a future version of PouchDB
I think this is related to the current version of usePouch, and I just wanted to give a heads up to see if this can be updated.

Steps to Reproduce

just using usePouch will show this warning on the console

Create React hooks for PouchDB

Summary

React Hooks are a powerful feature. And so are CouchDB and PouchDB!
With few hooks could enhance the use of PouchDB for React users!

Possible Solution

Create a small package with 4 hooks:

  • useDoc for accessing a Document.
  • useQuery for using views. Now it is useView
  • useAllDocs for using db.allDocs
  • usePouch for accessing the PouchDB instance.
    All hooks should also update to changes

Additional context

The first version can to expect to run on a local DB. A HTTP optimized version can be a later one.
useFind is a good candidate for a future version.

Add stale option to useQuery

Summary

The stale option is not yet supported in useQuery. But there are some use-cases.

Desired Behavior

useQuery could start a query with stale set to ok. And once it did finish loading, then make a second query without stale.
All future queries to that view shouldn't contain stale, even if other options did change.

Possible Solution

There could be a useRef that is set to the initial stale value. Once the first query did finish, the ref will be set to undefined.
Changes to the PouchDB instance or the view-name would reset it to the option value.

Additional context

The use case is to display fast something, and then update and fetch the newest data.
Sometimes new data didn't even sync yet. Stale data could improve the end-user experience.

Add manuel re-querying

Summary

Add a update function to the results of all hooks (except usePouch). It should manually start a re-query.
And add a new changes hook that takes a callback, which it calls on every change it subscribes to.

Desired Behavior

The changes hooks should only be for callbacks and not to return content like the other hooks.
It's callback should be stored in a ref, so that it can change on every render and not cause a re-subscription.

The update function of all hooks should just make a complete re-query.

Additionally every hooks could get a new option to control subscriptions. It could have following states:

  • subscribe (default) always subscribe to changes, as it is now.
  • manual don't subscribe to changes.
  • optimize only subscribe to changes for a local db.

The changes hook could have an additional option:

  • remote only subscribe to changes on a remote db. So that the changes hook could be used to set off the update function of an other hook.

Additional context

Currently all hooks subscribe to changes. But this might not always wanted.

Add a commune state machine

Summary

useDoc, useQuery and useFind do (or will) share much of their state. This could be unified in a commune state machine.

Desired Behavior

All 3 have the states:

  • loading
  • done
  • error

Also their result share a lot.

Possible Solution

Add a state machine module that implements the state changes.

Additional context

All 3 will share those states and there are more possible hooks down the road.

Add authentication hooks

Summary

Add some hooks for:

  • sign up
  • login
  • logout
  • session info
  • user doc
  • delete user
  • change password
  • change username

Desired Behavior

<Provider /> should have optional callbacks. For example onSignUp.
The hooks should then call the callback on the closest <Provider />. If it doesn't have that callback, move up to the next (requires #14). If the root-<Provider /> doesn't have that callback, then fail.

Possible Solution

The hooks should return a function.
The callbacks, and the function returned by the hooks, should have a similar API to pouchdb-authentication.

Additional context

The database is inherently linked to the user. When a user logs in, a remote database should be created with the auth options. Also when the user logs out the local database should be destroyed.

To handle everything in the Component that renders the <Provider /> would make it easier.

Extend package and docs to incorporate authentication

Authentication

I really like this project because of automatic subscription to remote changes. Although, I am quite new to React, implementing this package on my project was very straightforward and the docs were concise and easy to follow. Thank you contributors for you hard work! I was wondering if it would be possible to extend this project to include authenticating with remote Couch database. If it already supports it, I would like to learn about it and help with documentation (I am a complete noob on react).

Desired Behavior

The package should provide components that make it easy to authenticate against remote Couch database.

Possible Solution

Interface with PouchDB-Authentication package to facilitate easy authentication in react.

Add coc and contributing

Summary

Add community documentations.

  • A Code_of_Conduct
  • A CONTRIBUTING.md
  • Issue templates

Possible Solution

Use weallcontribute (CONTRIBUTING.md) and weallbehave (CODE_OF_CONDUCT.md).

The issue templates of CouchDB are quite good.

Additional context

This is needed!

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.