I'm a Vue developer that's trying to do a React App.
I'm trying to wrap CodeMirror in a React app and I'm running into some troubles. Not sure how to fix it.
I'm instantiating a CodeMirror editor and attaching some event handlers to it.
Those handlers are like so:
When you focus the editor, the isFocused
variable becomes true
.
When you focus out of the editor, the isFocused
variable becomes false
.
When you type in the editor you should do some action if the isFocused
variable is true.
In the last handler, I need to access a reactive variable set with useState
(isFocused
).
That variable is not reactive in the context of that function. It's read as the default value false
.
The component looks something like this:
import React, {useState, useEffect, useRef} from 'react';
import 'codemirror/lib/codemirror.css'
import 'codemirror/mode/javascript/javascript'
import CodeMirror from 'codemirror'
import './App.css';
function App() {
const textArea = useRef()
const [isFocused, setIsFocused] = useState(false)
const [data, setData] = useState('sample data')
const handleChange = () => {
console.log('isFocused->', isFocused);
if (isFocused) {
// do something here
}
}
const handleEditorFocus = () => {
setIsFocused(true)
}
const handleEditorBlur = () => {
setIsFocused(false)
}
useEffect(() => {
const editor = CodeMirror.fromTextArea(textArea.current)
editor.on('change', handleChange)
editor.on('focus', handleEditorFocus)
editor.on('blur', handleEditorBlur)
return () => {
editor.toTextArea()
}
}, []);
return (
<div>
{isFocused ? 'focused' : 'not focused'}
<textarea
ref={textArea}
value={data}
onChange={(e) => setData(e.target.value)}
></textarea>
</div>
)
};
export default App;
Please point me in the right direction with this issue.
Thank you!
UPDATE: I even made a repl.it here.
UPDATE 2
A better demo on stackblitz.
I basically need to have access to the instance
and change
params in the handleChange
function.
Add a useEffect
function with a callback to handleChange
and pass it isFocused
as an argument.
PS: Don't forget Boolean()
to display the state of isFocused otherwise it returns an object.
(See the demo link at the bottom of the page )
import React, { useState, useEffect, useRef } from 'react';
import 'codemirror/lib/codemirror.css';
import 'codemirror/mode/javascript/javascript';
import CodeMirror from 'codemirror';
export default function App() {
const textArea = useRef();
const [isFocused, setIsFocused] = useState(false);
const [data, setData] = useState('sample data');
const handleChange = isF => {
console.log('isFocused->', Boolean(isF)); // here
if (isFocused) {
// ...
}
};
const handleEditorFocus = () => {
setIsFocused(true);
};
const handleEditorBlur = () => {
setIsFocused(false);
};
useEffect(() => { // here
handleChange(isFocused);
}, [isFocused]);
useEffect(() => {
const editor = CodeMirror.fromTextArea(textArea.current);
editor.on('change', handleChange);
editor.on('focus', handleEditorFocus);
editor.on('blur', handleEditorBlur);
return () => {
editor.toTextArea();
};
}, []);
return (
<div>
{isFocused ? 'focused' : 'not focused'}
<textarea
ref={textArea}
value={data}
onChange={e => setData(e.target.value)}
/>
</div>
);
}
Demo: Stackblitz