I have an app where I want to move the read, write operations to a utility file i.e. away from ponent. I am trying to do it this way.
ponent.js
import { saveData } from './utils/fileSave.js';
class App extends Component {
saveContent() {
saveData(this.setState, data);
}
...
}
utils/fileSave.js
const saveData = (setState, data) => {
setState(data);
}
However, that leads to an error, saying 'TypeError: Cannot read property 'updater' of undefined'
Not sure if this is the correct way to go about it.
I have an app where I want to move the read, write operations to a utility file i.e. away from ponent. I am trying to do it this way.
ponent.js
import { saveData } from './utils/fileSave.js';
class App extends Component {
saveContent() {
saveData(this.setState, data);
}
...
}
utils/fileSave.js
const saveData = (setState, data) => {
setState(data);
}
However, that leads to an error, saying 'TypeError: Cannot read property 'updater' of undefined'
Not sure if this is the correct way to go about it.
Share Improve this question asked Aug 1, 2018 at 9:46 purezenpurezen 64312 silver badges29 bronze badges4 Answers
Reset to default 5It looks like you need to bind setState
before passing it to an external function.
saveData(this.setState.bind(this), data);
Need to bind this
to setState
.
saveData(this.setState.bind(this), data);
Working codesandbox demo
This is not a good idea to extract methods that rely on the context (ponent instance) to utility functions, primarily because this requires to take additional actions to make them work.
Since this.setState
is passed as a callback, it should be either bound to proper context:
saveData(this.setState.bind(this), data);
Or utility function should be defined as regular function and be called with proper context:
function saveData(data) {
this.setState(data);
}
class App extends Component {
saveContent() {
saveData.call(this, data);
}
...
}
This is the case where inheritance is preferable because it allows to get proper context naturally. saveData
can be reused via a mixin.
It can be assigned directly to class prototype:
function saveData(data) {
this.setState(data);
}
class App extends Component {
// saveData = saveData
// is less efficient but also a correct way to do this
saveContent() {
this.saveData(data);
}
...
}
App.prototype.saveData = saveData;
Or be applied via a decorator:
function saveData(target) {
return class extends target {
saveData(data) {
this.setState(data);
}
}
}
@saveData
class App extends Component {
saveContent() {
this.saveData(data);
}
...
}
Replace the bind function with arrow function will allow it works like a callback.
saveData((newState) => this.setState(newState), data);