Every keystroke in MarkdownViewer updated changedValue state, which was
fed back into MDXEditor's markdown prop and re-rendered the editor.
RealmWithPlugins runs plugin.update() for every plugin on every render
(dep-less useEffect), so each keystroke re-ran all ~15 plugin updates
including the toolbar tree — the dominant lag source. The markdown prop
is also only the editor's *initial* value, so feeding edits back was
semantically wrong.
- MarkdownEditor is wrapped in React.memo, its plugins array is
useMemo'd, and the translation callback is useCallback'd.
- MarkdownViewer tracks edits in a ref (read only at save) instead of
state, passes the immutable loaded content as value, and hands the
stable onChange callback directly — zero React re-renders per
keystroke.
Fixes#199 (upstream cloudreve/cloudreve#3584).
Authored By: TDvorak <info@tdvorak.dev>
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@ -205,7 +205,7 @@ Order = user-visible value first; each ships with backend + UI + tests.
- Own security review on top of upstream fixes: session/token entropy audit, SSRF guard re-test (NAT64 class), rate limiting on auth endpoints
- Fix upstream bug backlog by impact: ~~#3574 OOM~~ (done — paged tree walk + batched delete), ~~#3118/#3005 WebDAV large-file~~ (done — Content-Range assembly into one session; non-local policies get honest 501; single-PUT giant-file 500s are proxy/client timeouts, not fixable server-side), ~~#3375 SMTP auth discovery~~ (done — `smtp_auth` setting)
- #3454 (PG FK on upload) is **Pro-only** — `audit_logs` doesn't exist in this codebase. When B.5 adds our own audit log: insert the audit row in the same tx *after* the file row, never before.
- [ ] #199 (upstream #3584) — markdown editor lag: profile the MDX editor path; likely re-render-per-keystroke, evaluate debounce/virtualization or lighter editor before swapping libraries
- [x] #199 (upstream #3584) — markdown editor lag: root cause was per-keystroke React re-renders (changedValue state fed back into the editor's initial-markdown prop) re-running every plugin's `update()` hook (RealmWithPlugins has a dep-less effect). `MarkdownEditor` is now `memo`'d with a `useMemo`'d plugins array + stable `translation`; `MarkdownViewer` keeps edits in a ref (read at save) and passes the immutable loaded content — zero re-renders per keystroke
- [ ] #198 (upstream #3581) — "import files" task shows source storage policy "unknown": check task props → policy name resolution in admin import path (Pro report, likely same code path in CE)
- [ ] #200 (upstream #3586) — Pro crash on SIGHUP; log shows a clean signal-driven shutdown, no stack trace — watch for a CE repro, likely not actionable yet