8000 refactor(cache): improve cache and integrate reagent (#107) · homebaseio/homebase-react@35cf71a · GitHub
[go: up one dir, main page]

Skip to content < 10000 /span>

Commit 35cf71a

Browse files
authored
refactor(cache): improve cache and integrate reagent (#107)
1 parent 00bc018 commit 35cf71a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1220
-295
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ dist/
1313

1414
package-lock.json
1515
report.html
16-
pom.xml
1716
pom.xml.asc
1817
*.iml
1918
*.jar

README.md

Lines changed: 73 additions & 195 deletions
Large diffs are not rendered by default.

deps.edn

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
1-
{:paths ["src"]
1+
{:paths ["src/dev"
2+
"src/main"
3+
"src/test"]
24
:deps {thheller/shadow-cljs {:mvn/version "2.11.25"}
35
devcards/devcards {:mvn/version "0.2.7"}
46
datascript/datascript {:mvn/version "1.0.7"}
57
reagent/reagent {:mvn/version "1.0.0-alpha2"}
68
inflections/inflections {:mvn/version "0.13.2"}
79
binaryage/devtools {:mvn/version "1.0.2"}
8-
homebaseio/datalog-console {:git/url "https://github.com/homebaseio/datalog-console" :sha "97d5e5eb8994124ec8dc0029b33f2e88257b39b2"}
9-
;; homebaseio/datalog-console {:local/root "../datalog-console"}
10-
camel-snake-kebab/camel-snake-kebab {:mvn/version "0.4.2"}}}
10+
io.homebase/datalog-console {:mvn/version "0.2.2"}
11+
nano-id/nano-id {:mvn/version "1.0.0"}
12+
camel-snake-kebab/camel-snake-kebab {:mvn/version "0.4.2"}}
13+
:aliases {:jar {:replace-deps {com.github.seancorfield/depstar {:mvn/version "2.0.216"}}
14+
:exec-fn hf.depstar/jar
15+
:exec-args {:jar "homebase-react.jar" :sync-pom true}}
16+
:install {:replace-deps {slipset/deps-deploy {:mvn/version "0.1.5"}}
17+
:exec-fn deps-deploy.deps-deploy/deploy
18+
:exec-args {:installer :local :artifact "homebase-react.jar"}}
19+
:deploy {:replace-deps {slipset/deps-deploy {:mvn/version "0.1.5"}}
20+
:exec-fn deps-deploy.deps-deploy/deploy
21+
:exec-args {:installer :remote :artifact "homebase-react.jar"}}}}

doc/README.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Homebase React
2+
3+
[![CI](https://github.com/homebaseio/homebase-react/workflows/CI/badge.svg)](https://github.com/homebaseio/homebase-react/actions?query=workflow%3ACI)
4+
[![CD](https://github.com/homebaseio/homebase-react/workflows/CD/badge.svg)](https://github.com/homebaseio/homebase-react/actions?query=workflow%3ACD)
5+
[![License](https://img.shields.io/github/license/homebaseio/homebase-react.svg)](LICENSE)
6+
[![GitHub Repo stars](https://img.shields.io/github/stars/homebaseio/homebase-react?style=social)](https://github.com/homebaseio/homebase-react)
7+
[![Twitter Follow](https://img.shields.io/twitter/follow/homebase__io?label=Follow&style=social)](https://twitter.com/homebase__io)
8+
9+
> Use a datalog DB to manage react application state.
10+
11+
Supported languages, frameworks and DBs:
12+
13+
- JS + React + Datascript
14+
- CLJS + Reagent + Datascript
15+
- *Datahike support coming soon*
16+
17+
# Javascript + React
18+
19+
This is the Clojure docs site. Go here for [JS + React docs](https://homebase.io/docs/homebase-react).
20+
21+
# ClojureScript + Reagent
22+
23+
Start by adding `homebase-react`.
24+
25+
[![Clojars Project](https://img.shields.io/clojars/v/io.homebase/homebase-react.svg)](https://clojars.org/io.homebase/homebase-react)
26+
27+
Optionally add `datalog-console` and its corresponding [chrome extension](https://chrome.google.com/webstore/detail/datalog-console/cfgbajnnabfanfdkhpdhndegpmepnlmb?hl=en) to inspect the DB in your browser.
28+
29+
[![Clojars Project](https://img.shields.io/clojars/v/io.homebase/datalog-console.svg)](https://clojars.org/io.homebase/datalog-console)
30+
31+
## Quick Start
32+
33+
```clojure
34+
(ns homebase.dev.example.reagent.counter
35+
(:require
36+
[datascript.core :as d]
37+
[homebase.reagent :as hbr]
38+
[datalog-console.integrations.datascript :as datalog-console]))
39+
40+
(def db-conn (d/create-conn {}))
41+
(d/transact! db-conn [[:db/add 1 :count 0]]) ; Transact some starting data.
42+
(hbr/connect! db-conn) ; Connect homebase.reagent to the database.
43+
(datalog-console/enable! {:conn db-conn}) ; Also connect the datalog-console extension for better debugging.
44+
45+
(defn counter []
46+
(let [[entity] (hbr/entity db-conn 1)] ; Get a homebase.reagent/Entity. Note the use of db-conn and not @db-conn, this makes it reactive.
47+
(fn []
48+
[:div
49+
"Count: " (:count @entity) ; Deref the entity just like a reagent/atom.
50+
[:div
51+
[:button {:on-click #(d/transact! db-conn [[:db/add 1 :count (inc (:count @entity))]])} ; Use d/transact! just like normal.
52+
"Increment"]]])))
53+
```
54+
55+
[Live demo](https://homebaseio.github.io/homebase-react/index.html#!/homebase.dev.example.reagent)
56+
57+
## API
58+
59+
- [homebase.reagent](https://cljdoc.org/d/io.homebase/homebase-react/CURRENT/api/homebase.reagent)
60+
61+
## Performance
62+
63+
Our reactive query functions like `hbr/entity` and `hbr/q` will only trigger re-renders when their results change.
64+
65+
In the case of `hbr/entity` we track which attributes get consumed `(:attr @entity)` and only dispatch updates when those attributes are transacted.
66+
67+
`hbr/q` queries rerun on every transaction. If the result is different we re-render. We're looking into differential datalog and incremental view maintenance, but for typical datasets of tens of thousands of datoms the current performance is great. DOM updates tend to be much more costly, so just rerunning the queries still performs well as long as we don't repaint the DOM.
68+
69+
## Alternatives
70+
71+
- If your prefer `d/pull` over `d/entity` take a look at [Posh](https://github.com/denistakeda/posh). It supports less of the `d/q` API, but provides more tools for tuning performance.

doc/cljdoc.edn

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{:cljdoc.doc/tree
2+
[["Introduction" {:file "doc/README.md"}]
3+
["Examples" {:file "doc/examples.md"}]
4+
["Misc" {}
5+
["Tooling & Debugging" {:file "doc/tooling_debugging.md"}]
6+
["Performance" {:file "doc/performance.md"}]
7+
["Contribution" {:file "CONTRIBUTING.md"}]]]}

doc/examples.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Examples
2+
3+
Visit the [live demos](https://homebaseio.github.io/homebase-react/index.html#!/homebase.dev.example.reagent) devcards site to see some examples.

doc/performance.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Performance
2+
3+
Homebase React tracks the attributes consumed in each component via `homebase.reagent/Entity` and scopes those attributes to their respective `hbr/entity` reagent atom. Re-renders are only triggered when an attribute changes.
4+
5+
The default caching reduces unnecessary re-renders and virtual DOM thrashing a lot. That said, it is still possible to trigger more re-renders than you might want.
6+
7+
## Smart Prop Drilling
8+
9+
One top level `hbr/entity` + prop drilling the entity it returns will cause all children to re-render on any change to the parent or their siblings.
10+
11+
To fix this we recommend passing ids to children, not whole entities. Instead get the entity in the child with `(hbr/entity db-conn id)`. This creates a new scope for each child so they are not affected by changes in the state of the parent or sibling components.
12+
13+
### Good Prop Drilling
14+
15+
```clojure
16+
(defn friend [id]
17+
(let [[user] (hbr/entity db-conn id)]
18+
(fn []
19+
[:div (:user/name @user)])))
20+
21+
(defn friends [user-id]
22+
(let [[user] (hbr/entity db-conn user-id)]
23+
(fn [user-id]
24+
[:div
25+
(for [u (:user/friends @user)]
26+
[friend (:db/id u)])])))
27+
```
28+
29+
### Bad Prop Drilling
30+
31+
```clojure
32+
(defn friend [user]
33+
[:div (:user/name @user)])
34+
35+
(defn friends [user-id]
36+
(let [[user] (hbr/entity db-conn user-id)]
37+
(fn [user-id]
38+
[:div
39+
(for [u (:user/friends @user)]
40+
[friend u])])))
41+
```
42+
43+
## Query performance
44+
45+
`hbr/q` queries rerun on every transaction. If the result is different we re-render. We're looking into differential datalog and incremental view maintenance, but for typical datasets of tens of thousands of datoms the current performance is great. DOM updates tend to be much more costly, so rerunning the queries still performs well as long as we don't repaint the DOM.
46+
47+
If you are seeing UI slowdowns consider virtualizing large lists and only rendering DOM nodes that fit on the screen.

doc/tooling_debugging.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Tooling & Debugging
2+
3+
We've built a few tools to make debugging a bit more convenient.
4+
5+
## Custom chrome formatters
6+
If you develop with [Chrome](https://www.google.com/chrome/) or a Chromium browser like Brave or Edge you'll get significantly more meaningful logs for entities `(js/console.log an-entity)` due to our use of custom chrome :formatters. These custom formatters allow us to perform lazy database queries to fetch all of an entity's attributes, including references to other entities and all reverse references to the current entity. They let you access your entire data graph from the console, with any logged out entity as an entry point.
7+
8+
**To enable custom chrome formatters**
9+
10+
**1.** Add **[binaryage/cljs-devtools](https://github.com/binaryage/cljs-devtools)** to your app. Our entity formatters implement protocols defined in cljs-devtools and need cljs-devtools to work. Plus, if you've never used cljs-devtools you're in for a treat.
11+
12+
**2.** Open the preferences panel in chrome devtools by clicking the cog.
13+
14+
![image of chrome devtools preferences button](https://github.com/homebaseio/homebase-react/blob/master/public/images/enable_chrome_formatters_1.png?raw=true)
15+
16+
**3.** Toggle `Enabled custom formatters` on.
17+
18+
![image of chrome devtools custom formatters toggle](https://github.com/homebaseio/homebase-react/blob/master/public/images/enable_chrome_formatters_2.png?raw=true)
19+
20+
**4.** Keep the chrome console open and refresh the page. Any logged out entities should now have the custom formatting.
21+
22+
![image of custom entity chrome console logs](https://github.com/homebaseio/homebase-react/blob/master/public/images/enable_chrome_formatters_3.png?raw=true)
23+
24+
**Live demo:** open the console while on the [todo example](https://homebaseio.github.io/homebase-react/#!/homebase.dev.example.todo) page.
25+
26+
**Remember**: for custom formatters to work `(js/console.log an-entity)` must be called *after* you open the chrome console. Anything logged out before you open the console will not have custom formatting applied because chrome processes those logs in the background.
27+
28+
## Datalog Console Extension
29+
30+
We also integrate with the [Datalog Console](https://github.com/homebaseio/datalog-console) extension.
31+
32+
![image of datalog console extension](https://github.com/homebaseio/homebase-react/blob/master/public/images/datalog_console.png?raw=true)
33+
34+
It's still in an early stage of development, but we seek to expose all common DB administration capabilities here and let you connect to any Datalog database that implements the console's interface.
35+
36+
### Using the Datalog Console
37+
38+
1. [Add the extension to Chrome](https://chrome.google.com/webstore/detail/datalog-console/cfgbajnnabfanfdkhpdhndegpmepnlmb)
39+
2. Vist a page built with homebase-react [like this one](https://cljdoc.org/d/io.homebase/homebase-react/CURRENT/api/homebase.reagent), open the inspector, click the `Datalog DB` tab, and click `Load database` to try it out

docs/0100|Overview.md

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,24 @@
22

33
[![CI](https://github.com/homebaseio/homebase-react/workflows/CI/badge.svg)](https://github.com/homebaseio/homebase-react/actions?query=workflow%3ACI)
44
[![CD](https://github.com/homebaseio/homebase-react/workflows/CD/badge.svg)](https://github.com/homebaseio/homebase-react/actions?query=workflow%3ACD)
5-
[![NPM Version](https://img.shields.io/npm/v/homebase-react)](https://www.npmjs.com/package/homebase-react)
6-
[![Bundle Size](https://img.shields.io/bundlephobia/minzip/homebase-react)](https://www.npmjs.com/package/homebase-react)
75
[![License](https://img.shields.io/github/license/homebaseio/homebase-react.svg)](LICENSE)
86
[![GitHub Repo stars](https://img.shields.io/github/stars/homebaseio/homebase-react?style=social)](https://github.com/homebaseio/homebase-react)
97
[![Twitter Follow](https://img.shields.io/twitter/follow/homebase__io?label=Follow&style=social)](https://twitter.com/homebase__io)
108

11-
## What and Why
9+
Supported languages, frameworks and DBs:
1210

13-
As data and our need to annotate and organize it grows, so does our need for supporting state in *write-heavy* applications.
11+
- JS + React + Datascript
12+
- CLJS + Reagent + Datascript
13+
- *Datahike support coming soon*
1414

15-
To solve this problem, modern write-heavy applications such as Superhuman, Roam Research, and Facebook Messenger built their own embedded data layers to enable these more sophisticated user experiences.
15+
# ClojureScript + Reagent
1616

17-
Homebase React enables developers to access the same embedded datalog database as Roam Research through React hooks. You no longer have to build out a team or learn specialized tools like Clojure in order to build a delightful write-heavy application.
17+
This is the Javascript docs site. Go here for [CLJS + Reagent docs](https://cljdoc.org/d/io.homebase/homebase-react/CURRENT).
18+
19+
# Javascript + React
1820

19-
## Install
21+
Start by installing `homebase-react` [![NPM Version](https://img.shields.io/npm/v/homebase-react)](https://www.npmjs.com/package/homebase-react)
22+
[![Bundle Size](https://img.shields.io/bundlephobia/minzip/homebase-react)](https://www.npmjs.com/package/homebase-react)
2023

2124
```bash
2225
# NPM
@@ -26,6 +29,50 @@ npm install homebase-react --save
2629
yarn add homebase-react
2730
```
2831

32+
Optionally install the `datalog-console` [chrome extension](https://chrome.google.com/webstore/detail/datalog-console/cfgbajnnabfanfdkhpdhndegpmepnlmb?hl=en) to inspect the `homebase-react` DB in your browser.
33+
34+
## Quick Start
35+
36+
```js
37+
import { useCallback } from 'react'
38+
import { HomebaseProvider, useEntity, useTransact } from 'homebase-react'
39+
40+
const RootComponent = () => (
41+
// Create a DB and set some starting data
42+
<HomebaseProvider config={{ initialData: [{ counter: { id: 1, count: 0 }}] }}>
43+
<App/>
44+
</HomebaseProvider>
45+
)
46+
47+
const App = () => {
48+
// Get entity id = 1
49+
const [counter] = useEntity(1)
50+
const [transact] = useTransact()
51+
52+
return (
53+
<button onClick={() => {
54+
// Increment and save the count
55+
transact([{ counter: {
56+
id: 1, count: counter.get('count') + 1
57+
}}])
58+
}>
59+
{/* Render the count */}
60+
Increment {counter.get('count')}
61+
</button>
62+
)
63+
}
64+
```
65+
66+
[Live demo](https://homebaseio.github.io/homebase-react/#!/homebase.dev.example.counter)
67+
68+
## What and Why
69+
70+
As data and our need to annotate and organize it grows, so does our need for supporting state in *write-heavy* applications.
71+
72+
To solve this problem, modern write-heavy applications such as Superhuman, Roam Research, and Facebook Messenger built their own embedded data layers to enable these more sophisticated user experiences.
73+
74+
Homebase React enables developers to access the same embedded datalog database as Roam Research through React hooks. You no longer have to build out a team or learn specialized tools like Clojure in order to build a delightful write-heavy application.
75+
2976
## Testimonials
3077
> Homebase is executing on the vision of data usage, portability, and management we had when building Firebase. We never got there. I'm excited!
3178
>

docs/0200|Quick_Start.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ Adding `HomebaseProvider` automatically creates the database.
1111
```js
1212
import { HomebaseProvider } from 'homebase-react'
1313

14+
const config = { initialData: [{ counter: { id: 1, count: 0 }}] }
15+
1416
const RootComponent = () => (
15-
<HomebaseProvider>
17+
<HomebaseProvider config={config}>
1618
<App/>
1719
</HomebaseProvider>
1820
)

0 commit comments

Comments
 (0)
0