The code below redraws the melody variable--an array of midi numbers--as it changes (I am using react-piano to feed notes into vexflow). This approach simply deletes the previous drawing and draws a new one.
----------------------------------------------------------------------
import Vex from 'vexflow';
import {useEffect} from 'react';
import {midiVex, staveNotes} from './helper.js';
export default function Sheet (props) {
const clear = () => {
var myDiv = document.getElementById("boo")
while(myDiv.lastElementChild){
myDiv.removeChild(myDiv.lastElementChild);
}
}
const createContext = (divID) => {
const VF = Vex.Flow;
// Create an SVG renderer and attach it to the DIV element named "boo".
var div = document.getElementById(divID)
var renderer = new VF.Renderer(div, VF.Renderer.Backends.SVG);
// Size our SVG:
renderer.resize(500, 500);
// And get a drawing context:
return renderer.getContext();
}
const drawStave = (context) => {
const VF = Vex.Flow;
var stave = new VF.Stave(10, 40, 400);
// Add a clef and time signature.
stave.addClef("treble").addTimeSignature("4/4");
// Connect it to the rendering context and draw!
stave.setContext(context).draw();
return stave;
}
useEffect(() => {
drawStave(createContext('boo'));
}, []);
useEffect(() => {
const VF = Vex.Flow;
if(props.melody.length){
clear();
var context = createContext('boo');
var stave = drawStave(context);
var rawNotes = staveNotes(midiVex(props.melody));
var notes = [];
for(let i = 0; i < rawNotes.length; i++){
notes.push(new VF.StaveNote(rawNotes[i]));
}
var voice = new VF.Voice({num_beats:notes.length, beat_value:4});
voice.addTickables(notes);
var formatter = new VF.Formatter().joinVoices([voice]).format([voice], 400);
voice.draw(context,stave);
}
}, [props.melody]);
return (
<div id='boo'></div>
);