0
# Hook API
1
2
Hook-based interface for advanced integration scenarios, custom containers, and direct CodeMirror state management. The `useCodeMirror` hook provides lower-level access to CodeMirror functionality for complex use cases.
3
4
## Capabilities
5
6
### useCodeMirror Hook
7
8
Main hook for integrating CodeMirror with custom React components and containers.
9
10
```typescript { .api }
11
/**
12
* Hook for integrating CodeMirror with custom React components
13
* @param props - Configuration options extending ReactCodeMirrorProps
14
* @returns Object containing state, view, container, and their setters
15
*/
16
function useCodeMirror(props: UseCodeMirror): {
17
state: EditorState | undefined;
18
setState: React.Dispatch<React.SetStateAction<EditorState | undefined>>;
19
view: EditorView | undefined;
20
setView: React.Dispatch<React.SetStateAction<EditorView | undefined>>;
21
container: HTMLDivElement | null | undefined;
22
setContainer: React.Dispatch<React.SetStateAction<HTMLDivElement | null | undefined>>;
23
};
24
25
interface UseCodeMirror extends ReactCodeMirrorProps {
26
/** Custom container element for the editor */
27
container?: HTMLDivElement | null;
28
}
29
```
30
31
**Usage Examples:**
32
33
```typescript
34
import React, { useEffect, useRef } from "react";
35
import { useCodeMirror } from "@uiw/react-codemirror";
36
import { javascript } from "@codemirror/lang-javascript";
37
38
// Basic hook usage
39
function CustomEditor() {
40
const editor = useRef<HTMLDivElement>(null);
41
const { setContainer, view, state } = useCodeMirror({
42
container: editor.current,
43
value: "console.log('Hello World');",
44
extensions: [javascript()],
45
onChange: (value, viewUpdate) => {
46
console.log('Value changed:', value);
47
},
48
});
49
50
useEffect(() => {
51
if (editor.current) {
52
setContainer(editor.current);
53
}
54
}, [setContainer]);
55
56
return <div ref={editor} />;
57
}
58
59
// Advanced hook usage with multiple containers
60
function MultiEditorContainer() {
61
const editor1 = useRef<HTMLDivElement>(null);
62
const editor2 = useRef<HTMLDivElement>(null);
63
64
const { setContainer: setContainer1, view: view1 } = useCodeMirror({
65
container: editor1.current,
66
value: "// Editor 1",
67
theme: "light",
68
});
69
70
const { setContainer: setContainer2, view: view2 } = useCodeMirror({
71
container: editor2.current,
72
value: "// Editor 2",
73
theme: "dark",
74
});
75
76
useEffect(() => {
77
if (editor1.current) setContainer1(editor1.current);
78
if (editor2.current) setContainer2(editor2.current);
79
}, [setContainer1, setContainer2]);
80
81
const syncEditors = () => {
82
if (view1 && view2) {
83
const content = view1.state.doc.toString();
84
view2.dispatch({
85
changes: { from: 0, to: view2.state.doc.length, insert: content }
86
});
87
}
88
};
89
90
return (
91
<div>
92
<button onClick={syncEditors}>Sync Editors</button>
93
<div style={{ display: 'flex' }}>
94
<div ref={editor1} style={{ flex: 1 }} />
95
<div ref={editor2} style={{ flex: 1 }} />
96
</div>
97
</div>
98
);
99
}
100
```
101
102
### Hook State Management
103
104
The hook returns state management objects for direct manipulation of the editor.
105
106
```typescript { .api }
107
// Returned state objects
108
interface UseCodeMirrorReturn {
109
/** Current editor state - undefined before initialization */
110
state: EditorState | undefined;
111
/** State setter for programmatic state updates */
112
setState: React.Dispatch<React.SetStateAction<EditorState | undefined>>;
113
/** Current editor view - undefined before initialization */
114
view: EditorView | undefined;
115
/** View setter for programmatic view updates */
116
setView: React.Dispatch<React.SetStateAction<EditorView | undefined>>;
117
/** Current container element */
118
container: HTMLDivElement | null | undefined;
119
/** Container setter for attaching to DOM elements */
120
setContainer: React.Dispatch<React.SetStateAction<HTMLDivElement | null | undefined>>;
121
}
122
```
123
124
**Usage Example:**
125
126
```typescript
127
import React, { useEffect, useRef } from "react";
128
import { useCodeMirror } from "@uiw/react-codemirror";
129
import { EditorState } from "@codemirror/state";
130
import { javascript } from "@codemirror/lang-javascript";
131
132
function StateManagementExample() {
133
const containerRef = useRef<HTMLDivElement>(null);
134
const {
135
state,
136
setState,
137
view,
138
container,
139
setContainer
140
} = useCodeMirror({
141
value: "// Initial code",
142
extensions: [javascript()],
143
});
144
145
useEffect(() => {
146
if (containerRef.current) {
147
setContainer(containerRef.current);
148
}
149
}, [setContainer]);
150
151
const resetEditor = () => {
152
if (view) {
153
const newState = EditorState.create({
154
doc: "// Reset code",
155
extensions: [javascript()],
156
});
157
setState(newState);
158
}
159
};
160
161
const logState = () => {
162
if (state) {
163
console.log('Current state:', {
164
content: state.doc.toString(),
165
selection: state.selection.main,
166
lineCount: state.doc.lines,
167
});
168
}
169
};
170
171
return (
172
<div>
173
<button onClick={resetEditor} disabled={!view}>
174
Reset Editor
175
</button>
176
<button onClick={logState} disabled={!state}>
177
Log State
178
</button>
179
<div ref={containerRef} />
180
</div>
181
);
182
}
183
```
184
185
### External Change Tracking
186
187
The hook includes support for tracking external changes to prevent echo effects.
188
189
```typescript { .api }
190
/**
191
* Annotation for marking transactions as external changes
192
* Used internally to prevent onChange callbacks for programmatic updates
193
*/
194
const ExternalChange: import('@codemirror/state').AnnotationType<boolean>;
195
```
196
197
**Usage Example:**
198
199
```typescript
200
import React, { useRef } from "react";
201
import { useCodeMirror, ExternalChange } from "@uiw/react-codemirror";
202
203
function ExternalChangeExample() {
204
const containerRef = useRef<HTMLDivElement>(null);
205
const { view, setContainer } = useCodeMirror({
206
container: containerRef.current,
207
value: "// Original content",
208
onChange: (value, viewUpdate) => {
209
// This won't trigger for external changes
210
console.log('User changed content to:', value);
211
},
212
});
213
214
React.useEffect(() => {
215
if (containerRef.current) {
216
setContainer(containerRef.current);
217
}
218
}, [setContainer]);
219
220
const updateExternally = () => {
221
if (view) {
222
// This update won't trigger onChange
223
view.dispatch({
224
changes: {
225
from: 0,
226
to: view.state.doc.length,
227
insert: "// Updated externally"
228
},
229
annotations: [ExternalChange.of(true)],
230
});
231
}
232
};
233
234
return (
235
<div>
236
<button onClick={updateExternally}>Update Externally</button>
237
<div ref={containerRef} />
238
</div>
239
);
240
}
241
```
242
243
### Performance Optimization
244
245
The hook includes built-in performance optimizations for handling rapid updates.
246
247
**Usage Example:**
248
249
```typescript
250
import React, { useRef, useMemo } from "react";
251
import { useCodeMirror } from "@uiw/react-codemirror";
252
import { javascript } from "@codemirror/lang-javascript";
253
254
function OptimizedEditor() {
255
const containerRef = useRef<HTMLDivElement>(null);
256
257
// Memoize extensions to prevent unnecessary re-renders
258
const extensions = useMemo(() => [javascript()], []);
259
260
const { setContainer } = useCodeMirror({
261
container: containerRef.current,
262
value: "// Optimized editor",
263
extensions, // Stable reference prevents re-creation
264
onChange: React.useCallback((value) => {
265
// Debounced internally by the hook
266
console.log('Content updated:', value);
267
}, []),
268
});
269
270
React.useEffect(() => {
271
if (containerRef.current) {
272
setContainer(containerRef.current);
273
}
274
}, [setContainer]);
275
276
return <div ref={containerRef} />;
277
}
278
```