mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-03 18:22:57 +00:00
115 lines
3.2 KiB
Markdown
115 lines
3.2 KiB
Markdown
# Quill.js Emitter Error Fix
|
|
|
|
## Issue
|
|
```
|
|
Uncaught TypeError: can't access property "emit", this.emitter is undefined
|
|
```
|
|
|
|
This error occurred in `CustomRichEditor.tsx` when Quill.js tried to initialize or perform operations before its internal emitter was ready.
|
|
|
|
## Root Cause
|
|
1. **Unstable module configuration** - The `handleImageUpload` callback was included in `quillModules` dependencies, causing the modules object to recreate on every render
|
|
2. **Missing initialization guards** - Code attempted to access Quill editor methods before the editor was fully initialized
|
|
3. **Concurrent DOM mutations** - MutationObserver showed Quill was initializing while DOM was being modified
|
|
|
|
## Solution Applied
|
|
|
|
### 1. Stabilized Image Upload Handler
|
|
**Before:**
|
|
```typescript
|
|
const handleImageUpload = useCallback(() => { ... }, []);
|
|
|
|
const quillModules = useMemo(() => ({
|
|
toolbar: {
|
|
handlers: {
|
|
image: onImageUpload ? handleImageUpload : undefined,
|
|
},
|
|
},
|
|
}), [toolbarConfig, onImageUpload, handleImageUpload]); // handleImageUpload caused recreation
|
|
```
|
|
|
|
**After:**
|
|
```typescript
|
|
const handleImageUploadRef = useRef<() => void>();
|
|
|
|
useEffect(() => {
|
|
handleImageUploadRef.current = () => { ... };
|
|
});
|
|
|
|
const quillModules = useMemo(() => ({
|
|
toolbar: {
|
|
handlers: {
|
|
image: onImageUpload ? () => handleImageUploadRef.current?.() : undefined,
|
|
},
|
|
},
|
|
}), [toolbarConfig, onImageUpload]); // Only stable dependencies
|
|
```
|
|
|
|
### 2. Added Emitter Safety Checks
|
|
**Before:**
|
|
```typescript
|
|
const quill = quillRef.current?.getEditor();
|
|
if (quill) {
|
|
quill.focus();
|
|
// ... operations
|
|
}
|
|
```
|
|
|
|
**After:**
|
|
```typescript
|
|
const quill = quillRef.current?.getEditor();
|
|
if (quill && quill.root && quill.emitter) {
|
|
setTimeout(() => {
|
|
// Double-check Quill is still valid
|
|
if (!quill || !quill.emitter) {
|
|
toast({ title: 'Editor není připraven', ... });
|
|
return;
|
|
}
|
|
// ... operations
|
|
}, 100);
|
|
} else {
|
|
toast({ title: 'Editor není připraven', ... });
|
|
}
|
|
```
|
|
|
|
### 3. Added Stable Key to ReactQuill
|
|
```typescript
|
|
<ReactQuill
|
|
key={`quill-${readOnly ? 'readonly' : 'edit'}`}
|
|
// ... other props
|
|
/>
|
|
```
|
|
|
|
This prevents unnecessary remounting while allowing controlled reinitialization when mode changes.
|
|
|
|
### 4. Protected Image Manipulation Effect
|
|
```typescript
|
|
useEffect(() => {
|
|
const editor = quillRef.current?.getEditor();
|
|
if (!editor || !editor.root || !editor.emitter || readOnly) return;
|
|
// ... event handlers
|
|
}, [readOnly, toast]);
|
|
```
|
|
|
|
## Benefits
|
|
- ✅ Prevents Quill from reinitializing on every render
|
|
- ✅ Ensures operations only happen when editor is fully ready
|
|
- ✅ Provides user feedback when editor isn't ready
|
|
- ✅ Maintains stable component lifecycle
|
|
- ✅ Fixes the "this.emitter is undefined" error
|
|
|
|
## Testing
|
|
1. Create a new article in admin panel
|
|
2. Click "Vložit obrázek" or use toolbar image button
|
|
3. Select and crop an image
|
|
4. Verify image inserts without errors
|
|
5. Test image editing features (resize, filters, alignment)
|
|
6. Check browser console for absence of Quill errors
|
|
|
|
## Files Modified
|
|
- `frontend/src/components/common/CustomRichEditor.tsx`
|
|
|
|
## Related
|
|
- React Quill: https://github.com/zenoamaro/react-quill
|
|
- Quill.js: https://quilljs.com/
|