@rpcbase/client 0.107.0 → 0.111.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/hashState.js CHANGED
@@ -3,7 +3,8 @@ import {useState, useEffect, createContext, useContext, useCallback} from "react
3
3
  import LZString from "lz-string"
4
4
  import _isNil from "lodash/isNil"
5
5
  import _omitBy from "lodash/omitBy"
6
- import isEqual from "fast-deep-equal"
6
+
7
+ import isEqualValues from "./isEqualValues"
7
8
 
8
9
 
9
10
  const PAGE_NAVIGATION_EVENT = "RB_PAGE_NAVIGATION"
@@ -87,7 +88,7 @@ export const HashStateProvider = ({children}) => {
87
88
  ...parsed,
88
89
  }
89
90
  // apply only if changed
90
- if (!isEqual(hashState, newState)) {
91
+ if (!isEqualValues(hashState, newState)) {
91
92
  setHashState(newState)
92
93
  }
93
94
  }
@@ -0,0 +1,47 @@
1
+ /* @flow */
2
+ const isEqual = require("fast-deep-equal/react")
3
+
4
+
5
+ const isPlainObject = (obj) => {
6
+ return Object.prototype.toString.call(obj) === "[object Object]"
7
+ }
8
+
9
+ const sortValuesConsideringObjects = (values) => {
10
+ return values
11
+ .map(val => (isPlainObject(val) ? sortValuesConsideringObjects(Object.values(val)) : val))
12
+ .sort()
13
+ }
14
+
15
+ const isEqualValues = (a, b) => {
16
+ // Extract values and sort them if they belong to plain objects
17
+ const valsA = isPlainObject(a) ? sortValuesConsideringObjects(Object.values(a)) : a
18
+ const valsB = isPlainObject(b) ? sortValuesConsideringObjects(Object.values(b)) : b
19
+
20
+ if (valsA === null && valsB === null) {
21
+ return true
22
+ }
23
+
24
+ if (Array.isArray(valsA) || Array.isArray(valsB)) {
25
+ return isEqual(valsA, valsB)
26
+ }
27
+
28
+ // Check value count
29
+ if (valsA.length !== valsB.length) return false
30
+
31
+ // Compare the sorted arrays of values
32
+ for (let i = 0; i < valsA.length; i++) {
33
+ if (typeof valsA[i] === "object" && typeof valsB[i] === "object") {
34
+ if (!isEqualValues(valsA[i], valsB[i])) {
35
+ return false
36
+ }
37
+ } else {
38
+ if (!isEqual(valsA[i], valsB[i])) {
39
+ return false
40
+ }
41
+ }
42
+ }
43
+ return true
44
+ }
45
+
46
+
47
+ module.exports = isEqualValues
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpcbase/client",
3
- "version": "0.107.0",
3
+ "version": "0.111.0",
4
4
  "scripts": {
5
5
  "build-firebase": "webpack -c firebase/webpack.config.js",
6
6
  "build": "yarn build-firebase",
@@ -3,10 +3,13 @@ import assert from "assert"
3
3
  import {Platform} from "react-native"
4
4
  import {useCallback, useEffect, useState, useMemo, useId, useRef} from "react"
5
5
  import debug from "debug"
6
- import isEqual from "fast-deep-equal/react"
7
6
  import _omit from "lodash/omit"
8
7
  import LZString from "lz-string"
9
8
 
9
+ // TODO: remove this when stable
10
+ import isEqual from "fast-deep-equal/react"
11
+
12
+ import isEqualValues from "../../isEqualValues"
10
13
  import get_uid from "../../auth/get_uid"
11
14
 
12
15
  import useData from "./useData"
@@ -50,6 +53,7 @@ const getUseQuery = (register_query) => (
50
53
 
51
54
  const [source, setSource] = useState()
52
55
 
56
+ const dataRef = useRef(null)
53
57
  const [data, setData] = useData({useStorage, storageKey, hasInitiallySetFromStorage})
54
58
 
55
59
  const [error, setError] = useState()
@@ -69,6 +73,8 @@ const getUseQuery = (register_query) => (
69
73
 
70
74
  const applyNewData = (newData, context) => {
71
75
  setData(newData)
76
+ // set data in a ref so that it doesn't force re-rendering ie: unsubscribe / resubscribe
77
+ dataRef.current = newData
72
78
 
73
79
  // we only save network queries
74
80
  if (useStorage && context.source === "network") {
@@ -142,7 +148,7 @@ const getUseQuery = (register_query) => (
142
148
  hasFirstReply.current = true
143
149
 
144
150
  // skip if we already have the data
145
- if (isEqual(data, newData)) {
151
+ if (isEqualValues(data, newData)) {
146
152
  applyContext(context)
147
153
  return
148
154
  }
@@ -158,7 +164,11 @@ const getUseQuery = (register_query) => (
158
164
  return
159
165
  }
160
166
 
161
- if (!isEqual(data, newData)) {
167
+ if (isEqual(data, newData) && !isEqualValues(data, newData) && __DEV__) {
168
+ alert("EQUALITY MISMATCH THIS SHOULD NOT HAPPPEND!!!", data, newData)
169
+ }
170
+
171
+ if (!isEqualValues(dataRef.current, newData)) {
162
172
  applyContext(context)
163
173
  applyNewData(newData, context)
164
174
  } else {
@@ -170,8 +180,10 @@ const getUseQuery = (register_query) => (
170
180
  log && log("useQuery cleanup unsubscribe()")
171
181
  typeof unsubscribe === "function" && unsubscribe()
172
182
  }
183
+
184
+ // WARNING: do not change the hooks dependencies param or you risk creating infinite loops as it unsubscribes on cleanup
173
185
  // TODO: this isnt right we need to update on options change too
174
- }, [JSON.stringify(query), data, key])
186
+ }, [JSON.stringify(query), key])
175
187
 
176
188
 
177
189
  const loadNextPage = useCallback(() => {