When binding this to my addTimes function I get an error stating: Cannot read property 'bind' of undefined.
I am building in ReactjJS and Webpack.
I recently had another issue recent which people suggested:
this.addTimes = this.addTimes.bind(this);
See: Cannot read property 'setState' of undefined ReactJS
class Settings extends React.Component {
constructor(props) {
super(props);
this.state = {
times: []
};
}
render(){
this.addTimes = this.addTimes.bind(this);
Array.prototype.remove = function() {
var what, a = arguments, L = a.length, ax;
while (L && this.length) {
what = a[--L];
while ((ax = this.indexOf(what)) !== -1) {
this.splice(ax, 1);
}
}
return this;
};
var currentTicked = [];
var times =[]
function addTimes(id){
var index = times.indexOf(id);
if (!times.includes(id)) {
$("input:checkbox[name=time]:checked").each(function(){
currentTicked.push($(this).val());
times = times.concat(currentTicked)
times = jQuery.unique(times);
currentTicked = [];
});
} else if(times.includes(id)){
times = times.remove(id);
}
console.log(times);
this.setState = {
thims: times
}
}
In order to be able to bind addTimes to this in the constructor, addTimes must be a method on your class, not just a function in the render method.
class Settings extends React.Component {
constructor(props) {
super(props);
this.state = {
times: []
};
this.addTimes = this.addTimes.bind(this);
}
addTimes(id) {
// ...
}
}
If you want to create addTimes in the render method, you could just bind this to the function there:
function addTimes(id) {
// ...
}.bind(this);
Or your could make it into an arrow function instead:
const addTimes = (id) => {
// ...
}
Related
I have created a JavaScript class. I'm getting an error when I try to minify the code using javascript-minifier. Can you help me to fix this issue?
My code:
class Test {
onCompleted = () => {};
onDismissed = () => {};
onError = () => {};
isProgress = false;
popup;
payment;
startPayment(payment) {
this.payment = payment;
this.isProgress = true;
this.popup = window.open('---');
var timer = setInterval(function () {
if (this.Test.popup.closed) {
clearInterval(timer);
if (this.Test.isProgress) {
this.Test.isProgress = false;
this.Test.onDismissed();
}
}
}, 500);
}
}
const Test = new Test();
window.addEventListener('beforeunload', function () {
if (Test.popup != null && !Test.popup.closed) {
Test.popup.close();
}
});
window.Test = Test;
Error message:
// Error : Unexpected token: operator (=)
// Line : 2
// Col : 18
The way you are creating the class seems to be wrong. In classes you can use functions like this: onCompleted() {}; and you can create variables in constructor. I also fixed an issue where you have Test defined twice, one as the class and one as variable. I renamed variable to TestInstance
Here would be a fixed example:
class Test {
constructor() {
this.isProgress = false;
this.popup;
this.payment;
}
onCompleted () {};
onDismissed () {};
onError () {};
startPayment(payment) {
this.payment = payment;
this.isProgress = true;
this.popup = window.open("---");
var timer = setInterval(function () {
if (this.Test.popup.closed) {
clearInterval(timer);
if (this.Test.isProgress) {
this.Test.isProgress = false;
this.Test.onDismissed();
}
}
}, 500);
}
}
const TestInstance = new Test();
window.addEventListener("beforeunload", function () {
if (TestInstance.popup != null && !TestInstance.popup.closed) {
TestInstance.popup.close();
}
});
window.Test = TestInstance;
A minified version:
class Test{constructor(){this.isProgress=!1,this.popup,this.payment}onCompleted(){}onDismissed(){}onError(){}startPayment(s){this.payment=s,this.isProgress=!0,this.popup=window.open("---");var t=setInterval(function(){this.Test.popup.closed&&(clearInterval(t),this.Test.isProgress&&(this.Test.isProgress=!1,this.Test.onDismissed()))},500)}}const TestInstance=new Test;window.addEventListener("beforeunload",function(){null==TestInstance.popup||TestInstance.popup.closed||TestInstance.popup.close()}),window.Test=TestInstance;
How can we dynamically/programmatically extend a javascript class?
More concretely, given something like
class Polygon {
constructor(area, sides) {
this.area = area;
this.sides = sides;
}
}
const Rectangle = extend(Polygon, (length, width) => {
super(length * width, 4);
this.length = length;
this.width = width;
});
how can we implement something like extend such that it behaves the same as
class Rectangle extends Polygon {
constructor(length, width) {
super(length * width, 4);
this.length = length;
this.width = width;
}
}
?
There are three problems here:
(1) super is only available inside object methods, so there is no way to access super in an arrow function. That needs to be somehow replaced by a regular function call.
(2) Classes can only be constructed, not called (unlike functions acting as constructors). Therefore you cannot just .call the classes constructor onto the "subclass" instance. You have to create an instance of the superclass and copy that into the subclass, eventually loosing getters / setters.
(3) Arrow functions have a lexical this, so you cannot access the instance with this inside an arrow function.
Given these three problems, a viable alternative would be:
function extend(superclass, constructor) {
function Extended(...args) {
const _super = (...args) => Object.assign(this, new superclass(...args));
constructor.call(this, _super, ...args);
}
Object.setPrototypeOf(Extended, superclass);
Object.setPrototypeOf(Extended.prototype, superclass.prototype);
return Extended;
}
const Rectangle = extend(Polygon, function(_super, length, width) {
_super(/*...*/);
/*...*/
});
But honestly ... what's wrong with the native class ... extends ?
After some hacking around, I've found that this horrifyingly works.
function extend(superclass, construct) {
return class extends superclass {
constructor(...args) {
let _super = (...args2) => {
super(...args2)
return this;
};
construct(_super, ...args);
}
};
}
const Rectangle = extend(Polygon, function(_super, length, width) {
let _this = _super(length * width, 4);
_this.length = length;
_this.width = width;
});
class A {
m () {
console.log('A')
}
}
class B extends A {
m () {
console.log('B')
}
}
var a = new A()
var b = new B()
a.m()
b.m()
const MixinClass = superclass =>
class extends superclass {
m () {
console.log('extended')
}
}
const extendsAnyClass = AnyClass =>
class MyMixinClass extends MixinClass(AnyClass) {}
var AA = extendsAnyClass(A)
var BB = extendsAnyClass(B)
var aa = new AA()
var bb = new BB()
aa.m()
bb.m()
This worked for me:
const extend = SuperClass => class E extends SuperClass {
constructor() {
super('E')
}
}
class A {
constructor(arg) {
console.log('Hello from ' + arg)
}
}
class B {
constructor(arg) {
console.log('Hi from ' + arg)
}
}
const C = extend(A)
const D = extend(B)
new C() // Hello from E
new D() // Hi from E
This will dynamically extend E for any given parent class
https://jsfiddle.net/1s0op2ng/
I am trying to set the state in React inside my function, however I get an error message stating: Cannot read property 'setState' of undefined.
Below is my code, I call the state in the constructor then I am setting the state in the addTimes function and binding this to that function, however I am still getting the error.
class Settings extends React.Component {
constructor(props) {
super(props);
this.state = {
times: []
};
}
render(){
Array.prototype.remove = function() {
var what, a = arguments, L = a.length, ax;
while (L && this.length) {
what = a[--L];
while ((ax = this.indexOf(what)) !== -1) {
this.splice(ax, 1);
}
}
return this;
};
var currentTicked = [];
var times =[]
function addTimes(id){
var index = times.indexOf(id);
if (!times.includes(id)) {
$("input:checkbox[name=time]:checked").each(function(){
currentTicked.push($(this).val());
times = times.concat(currentTicked)
times = jQuery.unique(times);
});
} else if(times.includes(id)){
times.remove(id)
}
console.log(times);
addTimes = () => {
this.setState({
times: times
});
}
}
you haven't bound the function to the class. try doing
addTimes = (id) => {
// code here
}
in the component class
Try with an arrow function:
addTimes = id => {
var index = times.indexOf(id);
if (!times.includes(id)) {
$("input:checkbox[name=time]:checked").each(function(){
currentTicked.push($(this).val());
times = times.concat(currentTicked)
times = jQuery.unique(times);
});
} else if(times.includes(id)){
times.remove(id)
}
console.log(times);
addTimes = () => {
this.setState({
times: times
});
}
}
Or, bind thisin addTimesfunction like this :
constructor(props) {
super(props);
this.state = {
times: []
this.addTimes = this.addTimes.bind(this);
};
}
better to use es6 syntax. try with below code.
class Settings extends React.Component {
constructor(props) {
super(props);
this.state = {
times: []
};
let times = [];
let currentTicked = [];
this.addTimes = this.addTimes.bind(this);
}
addTimes(id) {
let index = times.indexOf(id);
if (!times.includes(id)) {
$("input:checkbox[name=time]:checked").each(function(){
currentTicked.push($(this).val());
times = times.concat(currentTicked)
times = jQuery.unique(times);
});
} else if(times.includes(id)){
times.remove(id)
}
this.setState({
times: times
});
}
render(){
this.addTimes;
return (
Array.prototype.remove = function() {
var what, a = arguments, L = a.length, ax;
while (L && this.length) {
what = a[--L];
while ((ax = this.indexOf(what)) !== -1) {
this.splice(ax, 1);
}
}
return this;
}
);
}
}
I just learned a little of react-redux and stuck at such problems I cannot understand and fix at least 4 days long.
First of the problem stands and can be seen at inspectors console (I use Chrome).
I have event handler at <div> inside react component. It have to be called at onClick event but it triggers at each load or reload of site.
Second, stands somewhere near reducer's function. It says me in console (dev tools) that reducers received action 'TOGGLE_TILE' and returned undefined instead of object. Should notice that reducer successfully receives state, action properties and makes some operations inside but as result nothing normal returnes.
The code of my reducer, actions, main, container, presentation components and functions provide. Please answer expanded as you can, i want to understand whats wrong and not make this mistake inside code twice.
ALSO! I using redux-thunk middleware (to functional callbacks inside actions, you know).
Inside i have:
index.js - main component
const store = createStore(reducer, applyMiddleware(thunk));
ReactDOM.render(
<Provider store={store}>
<AppContainer />
</Provider>,
document.getElementById('root')
);
registerServiceWorker();
actions.js
export function toggle(id){
return{
type: 'TOGGLE_TILE',
id
};
}
export function toggleTile(id){
return dispatch => {
console.log('toggling');
dispatch(toggle(id));
};
}
tiles.js - Reducer
var i = 0;
function tiles(state = tilesContainer, action){
var openedTiles = [];
switch (action.type) {
case 'TOGGLE_TILE':
if(i < 2){
console.log('i: '+i);
state.map((value) => {
var newOpen;
if(!value.opened && action.id === value.id){
newOpen = Object.assign({}, value, {
opened: !value.opened
});
openedTiles.push(newOpen);
i++;
console.log(i, value.opened, newOpen, openedTiles);
}
return newOpen, i;
});
}else if(i === 2){
var curr, prev;
openedTiles.map((value) => {
if(!prev){
prev = value;
}else{
curr = value;
console.log("Prev and curr: "+prev, curr);
if(curr.name === prev.name){
var currRes = Object.assign({}, curr, {
disappeared: !curr.disappeared
});
var prevRes = Object.assign({}, prev, {
disappeared: !prev.disappeared
});
return {currRes, prevRes};
} else {
let currRes = Object.assign({}, curr, {
opened: !curr.opened
});
let prevRes = Object.assign({}, prev, {
opened: !prev.opened
})
return currRes, prevRes;
}
}
});
}else{
return state;
}
default:
return state;
}
console.log("tiles: "+state.forEach(value => console.log(value)));
}
const reducers = combineReducers({
tiles
});
export default reducers;
AppContainer.jsx
const mapStateToProps = (state) => {
return {
tiles: state.tiles
};
};
const mapDispatchToProps = (dispatch) => {
return {
toggle: id => {
// console.log(id);
dispatch(toggleTile(id));
}
};
};
class AppContainer extends Component {
constructor(props){
super(props);
}
componentDidMount(){
}
render() {
var prop = this.props;
console.log(prop);
return (
<div>
<AppView prop={prop} />
</div>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(AppContainer);
AppView.js
class AppView extends React.Component {
constructor(props){
super(props);
this.state = {
tiles: this.props.prop.tiles,
};
this.showTiles = this.showTiles.bind(this);
this.defineRatio = this.defineRatio.bind(this);
this.toggleTile = this.toggleTile.bind(this);
}
componentDidMount(){
this.defineRatio();
}
componentWillMount(){
}
defineRatio(){
var imgClass;
let tile = document.querySelectorAll('img');
tile.forEach((value) => {
var imgSrc, imgW, imgH;
function defineImage(imgSrc){
var img = new Image();
img.src = imgSrc;
img.onload = function() {
return {
src:imgSrc,
width:this.width,
height:this.height};
};
return img;
}
var x = defineImage(value.src);
x.addEventListener('load',function(){
imgSrc = x.src;
imgW = x.width;
imgH = x.height;
// console.log(value.src, imgW, imgH);
var imgClass = (imgW / imgH > 1) ? 'wide' : 'tall';
value.classList += imgClass;
});
});
}
toggleTile(id){
this.props.prop.toggle(id);
}
showTiles(){
const boxElems = this.state.tiles.map((value, index) => {
var styles = {background: 'black'};
var tileState = value.opened ? '' : styles;
var imgState = value.opened ? 'opened ' : 'closed ';
var elem = <img key={value.id} src={value.src} alt="" className={imgState} />;
var boxElem = <div style={tileState} className="tile-box " onClick={this.toggleTile(value.id)} key={index}>{elem}</div>;
return boxElem;
});
return boxElems;
}
render(){
var tiles = this.showTiles();
return (
<div className="tiles-box">
<div className="tiles">
{tiles}
</div>
</div>
);
}
}
export default AppView;
First problem can be solved by replacing
onClick={this.toggleTile(value.id)}
with onClick={(e) => this.toggleTile(value.id)} First statement is just invoking this.toggleTile(value.id) immediately and setting the return value to OnClick event.
Regarding second you are not returning any thing from your reducer , hence state is undefined.
if(i < 2){
console.log('i: '+i);
state.map((value) => {
var newOpen;
if(!value.opened && action.id === value.id){
newOpen = Object.assign({}, value, {
opened: !value.opened
});
openedTiles.push(newOpen);
i++;
console.log(i, value.opened, newOpen, openedTiles);
}
return newOpen, i;
});
}
What is this return newOpen, i it should be return newOpen, also as this return is in a map function you have to return the mapped array as well
so use return state.map((value) => {
the problem that you have is that you are actually calling the function inside your div, thus it will get triggered each time you enter the view, so replace the following code on your showTiles()
var boxElem = <div style={tileState} className="tile-box " onClick={this.toggleTile(value.id)} key={index}>{elem}</div>;
to this:
var boxElem = <div style={tileState} className="tile-box " onClick={e => this.toggleTile(value.id)} key={index}>{elem}</div>;
and actually this should fix the error for the point 2.
I'm having trouble accessing this.state in functions inside my component. I already found this question on SO and added the suggested code to my constructor:
class Game extends React.Component {
constructor(props){
super(props);
...
this.state = {uid: '', currentTable : '', currentRound : 10, deck : sortedDeck};
this.dealNewHand = this.dealNewHand.bind(this);
this.getCardsForRound = this.getCardsForRound.bind(this);
this.shuffle = this.shuffle.bind(this);
}
// error thrown in this function
dealNewHand(){
var allCardsForThisRound = this.getCardsForRound(this.state.currentRound);
}
getCardsForRound(cardsPerPerson){
var shuffledDeck = this.shuffle(sortedDeck);
var cardsForThisRound = [];
for(var i = 0; i < cardsPerPerson * 4; i++){
cardsForThisRound.push(shuffledDeck[i]);
}
return cardsForThisRound;
}
shuffle(array) {
...
}
...
...
It still does not work. this.state.currentRound is undefined. What is the problem?
I came up with something that worked. I changed the code for binding getCardsForRound in the constructor to:
this.getCardsForRound = this.getCardsForRound.bind(this, this.state.currentRound);
Write your functions this way:
dealNewHand = () => {
var allCardsForThisRound =
this.getCardsForRound(this.state.currentRound);
}
getCardsForRound = (cardsPerPerson) => {
var shuffledDeck = this.shuffle(sortedDeck);
var cardsForThisRound = [];
for(var i = 0; i < cardsPerPerson * 4; i++){
cardsForThisRound.push(shuffledDeck[i]);
}
return cardsForThisRound;
}
http://www.react.express/fat_arrow_functions
the binding for the keyword this is the same outside and inside the fat arrow function. This is different than functions declared with function, which can bind this to another object upon invocation. Maintaining the this binding is very convenient for operations like mapping: this.items.map(x => this.doSomethingWith(x)).