Skip to content

Commit fe65ec0

Browse files
author
CodeBuddy Attribution Bot
committed
fix(attribution): 实时监听 API 缺乏初始数据就绪通知机制 (issue_mnrzm5ru_70sm9m)
1 parent d98ba09 commit fe65ec0

2 files changed

Lines changed: 50 additions & 2 deletions

File tree

config/.claude/skills/no-sql-web-sdk/SKILL.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ Keep local `references/...` paths for files that ship with the current skill dir
4646
- Querying before the user is signed in when the collection rules require identity.
4747
- Using `wx.cloud.database()` or Node SDK patterns in browser code.
4848
- Initializing CloudBase lazily with dynamic imports instead of a shared synchronous app instance.
49+
- For realtime UI, assuming the listener is ready immediately after calling `watch()`. Treat the first `onChange` snapshot whose `docChanges` contain `dataType: 'init'` as the initial data ready signal before rendering room state, enabling actions, or concluding that the query returned no rows.
4950
- Treating security rules as result filters rather than request validators.
5051
- For CMS-style collections that need **app-level admin users** to edit/delete all records while editors can only edit/delete their own records, do not oversimplify the rule to `READONLY`. A validated pattern is a `CUSTOM` rule that reads role from `user_roles` by `auth.uid` and combines it with `doc.authorId == auth.uid`, while frontend writes can stay on `.doc(id).update()` / `.doc(id).remove()`.
5152
- Forgetting pagination or indexes for larger collections.
@@ -119,6 +120,11 @@ Important rules:
119120
- Database errors must become readable UI or application errors, not silent failures.
120121
- For writes, do not treat a resolved promise as success by default. Check write result fields such as `updated` / `deleted` or surfaced `code` / `message`.
121122

123+
5. **Handle realtime initialization explicitly**
124+
- `.watch()` becomes usable only after the first `onChange` snapshot arrives.
125+
- Use the snapshot whose `docChanges` include `dataType: 'init'` as the canonical "initial data is ready" event.
126+
- Until that event arrives, keep loading state explicit and avoid enabling turn-based actions that depend on the queried documents.
127+
122128
## Quick examples
123129

124130
### Simple query

config/.claude/skills/no-sql-web-sdk/realtime.md

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,40 @@ Create a real-time data listener that returns a `watcher` object.
8888
- `add`: New document added
8989
- `delete`: Document deleted
9090

91+
## Initial Readiness Contract
92+
93+
Calling `.watch()` only starts the listener setup. Do not assume the queried data is ready immediately after `watch()` returns.
94+
95+
- Treat the first `onChange` snapshot whose `docChanges` contain `dataType: 'init'` as the canonical "initial data is ready" signal.
96+
- Until that `init` snapshot arrives, keep loading state explicit.
97+
- Do not enable turn-based actions, render room state as authoritative, or conclude that the query returned no rows before the `init` snapshot.
98+
99+
Example:
100+
101+
```javascript
102+
let initialReady = false;
103+
104+
const watcher = db.collection("rooms")
105+
.where({ roomId })
106+
.watch({
107+
onChange(snapshot) {
108+
const isInit = snapshot.docChanges?.some(
109+
change => change.dataType === 'init'
110+
);
111+
112+
syncRoomState(snapshot.docs);
113+
114+
if (isInit && !initialReady) {
115+
initialReady = true;
116+
setLoading(false);
117+
}
118+
},
119+
onError(error) {
120+
handleWatchError(error);
121+
}
122+
});
123+
```
124+
91125
**Watcher object methods:**
92126
- `watcher.close()`: Close monitoring and release resources
93127
@@ -120,10 +154,18 @@ import { useEffect } from 'react';
120154

121155
function ChatRoom({ roomId }) {
122156
useEffect(() => {
157+
let initialReady = false;
123158
const watcher = db.collection("messages")
124159
.where({ chatRoomId: roomId })
125160
.watch({
126-
onChange: handleNewMessages,
161+
onChange(snapshot) {
162+
handleNewMessages(snapshot);
163+
164+
if (!initialReady && snapshot.docChanges?.some(change => change.dataType === 'init')) {
165+
initialReady = true;
166+
setLoading(false);
167+
}
168+
},
127169
onError: handleError
128170
});
129171

@@ -133,4 +175,4 @@ function ChatRoom({ roomId }) {
133175
};
134176
}, [roomId]);
135177
}
136-
```
178+
```

0 commit comments

Comments
 (0)