Search code examples
javascriptreactjscachingsetstate

Error when passing setState in a React class component to an external function?


Assume data has already been cached in sessionStorage. I have hydrateStateWithSessionStorage in an external CacheService.js file. I import this file. When I try to pass this.setState to this function, I get this error:

Uncaught TypeError: Cannot read property 'updater' of undefined

How can I solve this? I could possibly use a the React hook useState and pass the setter function, but what if I want to use a class component instead of functional component? Or am I simply unable to pass setState because it implicitly uses the 'this' keyword in its implementation?

   hydrateStateWithSessionStorage(state, setState) {
    // for all items in state
    for (let key in state) {

        // if the key exists in localStorage
        if (sessionStorage.hasOwnProperty(key)) {
            // get the key's value from localStorage
            let value = sessionStorage.getItem(key);
            // console.log(value)
            // parse the localStorage string and setState
            try {
                value = JSON.parse(value);
                console.log('before')
                setState({ [key]: value });
                console.log('after')
            } catch (e) {
                // handle empty string
                setState({ [key]: value });
            }
        }
    }
}


//in the component consuming CacheService
//this.Cache = new CacheService(); //in the constructor

componentDidMount() {
    this.Cache.hydrateStateWithLocalStorage(this.state, this.setState);
    this.Auth.fetch('api/upcomingbill/').then((data) => {
        this.setState({ list: data })
    });
}

Solution

  • How about this?

    componentDidMount() {
        this.Cache.hydrateStateWithLocalStorage(this);
        this.Auth.fetch('api/upcomingbill/').then((data) => {
            this.setState({ list: data })
        });
    }
    

    And then using setState like so...

    hydrateStateWithSessionStorage(ReactComp) {
        for (let key in ReactComp.state) {
            ...
            ReactComp.setState({ [key]: value });
            ....
        }
    }
    

    FYI, this is not a React specific issue. The reason you are getting that error is, you are passing just a method that internally uses "this" (of that particular class) to the hydrateStateWithSessionStorage function. By the time, that method is called in the function, the scope has changed and "this" is not defined or not the same anymore.