Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

this is undefined in React method

I am trying to make a simple synthesizer with React and the Web Audio API and having trouble with some methods. Here is my code:

import * as React from "react"

class Synth extends React.Component {

    constructor(props) {
        super(props);
        this.state = {value: 0.5};
    
        this.handleChange = this.handleChange.bind(this);
        this.setup = this.setup.bind(this);
        this.createKey = this.createKey.bind(this);
        this.componentDidMount = this.componentDidMount.bind(this);
        this.audioContext = null;
        this.oscList = [];
        this.mainGainNode = null;
        this.wavePicker = document.querySelector("select[name='waveform']");
        this.volumeControl = document.querySelector("input[name='volume']");

        this.noteFreq = null;
        this.customWaveform = null;
        this.sineTerms = null;
        this.cosineTerms = null;
    }
    componentDidMount(){
        this.setup();
    }

    handleChange(event) {
        this.setState({
            value: event.target.value
        });
    }

    createNoteTable(){
        let noteFreq = [];
        for (let i=0; i< 9; i++) {
            noteFreq[i] = [];
        }

        noteFreq[3]["C"] = 130.81;
        noteFreq[3]["C#"] = 138.59;
        noteFreq[3]["D"] = 146.83;
        noteFreq[3]["D#"] = 155.56;
        noteFreq[3]["E"] = 164.81;
        noteFreq[3]["F"] = 174.61;
        noteFreq[3]["F#"] = 185.00;
        noteFreq[3]["G"] = 196.00;
        noteFreq[3]["G#"] = 207.65;
        //etc...
        return noteFreq;
    }
    createKey(note, octave, freq){
        console.log("createKey() is firing");
        let keyElement = document.createElement("li");

        switch (freq) {
            case 130.81:
                keyElement.className = "white c1"
                break;
            case 146.83:
                keyElement.className = "black cs1"
                break;
            case 164.81:
                keyElement.className = "white c1"
                break;
            case 174.61:
                keyElement.className = "white d1"
                break;
            //etc...
        
            default:
                break;
        }
        keyElement.dataset["freq"] = freq;
        keyElement.dataset["note"] = note;
        keyElement.dataset["octave"] = octave;
        keyElement.addEventListener("mousedown", this.notePressed, false);
        keyElement.addEventListener("mouseup", this.noteReleased, false);
        keyElement.addEventListener("mouseover", this.notePressed, false);
        keyElement.addEventListener("mouseleave", this.noteReleased, false);

        return keyElement;
    }
    
    setup(){
        
        this.audioContext = new (window.AudioContext || window.webkitAudioContext)();

        this.noteFreq = this.createNoteTable();

        
        this.mainGainNode = this.audioContext.createGain();
        this.mainGainNode.connect(this.audioContext.destination);
        this.mainGainNode.gain.value = this.state.value;
        
        this.noteFreq.forEach(function(keys, idx) {
            let keyList = Object.entries(keys);
            let octaveElem = document.createElement("div");
            keyList.forEach(function(key){

                console.log("key[0] = " + key[0]);
                console.log("idx = " + idx);
                console.log("key[1] = " + key[1]);
                try {
                    octaveElem.appendChild(this.createKey(key[0], idx, key[1]));
                } catch(error){
                    console.log("Cannot create key... " + error);
                }
            });
        });
    
        this.sineTerms = new Float32Array([0, 0, 1, 0, 1]);
        this.cosineTerms = new Float32Array(this.sineTerms.length);
        this.customWaveform = this.audioContext.createPeriodicWave(this.cosineTerms, this.sineTerms);
    
        for (let i=0; i<9; i++) {
            this.oscList[i] = {};
        }
    }

then I have the notePressed() and noteReleased() functions but these seem to work fine.

The problem is when this.createKey() is called I get this error :
TypeError: Cannot read properties of undefined (reading ‘createKey’)

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

As you can see, I tried binding pretty much every method I have to see if it would help but it didn’t. Any help will be greatly appreciated.

>Solution :

Your error is probably due to the function keyword in your forEach loops. There you lose your this scope. You can fix it by using for of or an arrow function.

this.noteFreq.forEach((keys, idx) => {
    ...
    keyList.forEach((key) => { 
        ...
    }
}

Also, your code looks more like a normal ES6 class, and not a React class. In React, you don’t use document.createElement and element.appendChild. Instead, you should use the render() function to render the document.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading