Reputation: 17
I got this Error message: "TypeError: Cannot read property 'addEventListener' of undefined" and I don't know why. I think it has to do with the fact that variable "el" loads the first time with the value of zero but I am not sure and I dont know how to solve that issue.
EDIT: I updated the code with the help of the answers. Now I got a new error message "TypeError: Cannot set property 'value' of undefined" https://jsfiddle.net/Van_Gram/4vofz6jh/7/
import React, { Component } from 'react';
import { connect } from 'react-redux'
import { addToCart } from './actions/cartActions'
import StackGrid from "react-stack-grid"
import Tilt from 'react-tilt'
// normally these would be `import` statements bundled by webpack
const { ReactDOM } = window;
class Home extends Component{
constructor(props) {
super(props);
this.unlockStartHandler = this.unlockStartHandler.bind(this);
this.unlockEndHandler = this.unlockEndHandler.bind(this);
this.animateHandler = this.animateHandler.bind(this);
this.successHandler = this.successHandler.bind(this);
this.maxValue = 150;
this.speed = 12;
this.currValue = 0;
this.rafID = null;
}
/*componentDidMount() {
// bind events
this.inputRange.addEventListener('mousedown', this.unlockStartHandler, false);
this.inputRange.addEventListener('mousestart', this.unlockStartHandler, false);
this.inputRange.addEventListener('mouseup', this.unlockEndHandler, false);
this.inputRange.addEventListener('touchend', this.unlockEndHandler, false);
}*/
// listen for unlock
unlockStartHandler(e) {
// clear raf if trying again
window.cancelAnimationFrame(this.rafID);
// set to desired value
this.currValue = +e.target.value;
}
unlockEndHandler(e) {
// store current value
this.currValue = +e.target.value;
// determine if we have reached success or not
if(this.currValue >= this.maxValue) {
this.successHandler();
this.sendData();
}
else {
this.rafID = window.requestAnimationFrame(this.animateHandler);
}
}
// handle range animation
animateHandler() {
// update input range
this.inputRange.value = this.currValue;
// determine if we need to continue
if(this.currValue > -1) {
window.requestAnimationFrame(this.animateHandler);
}
// decrement value
this.currValue = this.currValue - this.speed;
}
// handle successful unlock
successHandler = (prevState) => {
// alert('unlocked');
// reset input range
this.inputRange.value = 0;
};
sendData = () => {
this.props.parentCallback(null);
}
callbackFunction = (childData) => {
/*this.setState((prevState) => ({
counter: prevState.counter + 1,
}));*/
}
handleClick = (id)=>{
this.props.addToCart(id);
}
render(){
let itemList = this.props.items.map(item=>{
return(
<Tilt className="Tilt" options={{ max : 10 }, { perspective : 3000 }, {scale : 0.97}} >
<div className="card" key={item.id}>
<div className="card-image">
<img src={item.img} alt={item.title}/>
</div>
<div className="card-content">
<h2 className="card-title">{item.title}</h2>
<p>{item.desc}</p>
<div className="slider">
<h3>Swipe um zu bestellen</h3>
<input
type="range"
defaultValue={0}
min={0}
max={150}
className="pullee"
/*ref={(el) => { this.inputRange = el; }}*/
/>
</div>
<span to="/" className="btn-floating halfway-fab waves-effect waves-light red" onClick={()=>{this.handleClick(item.id)}}><i className="material-icons">add</i></span>
</div>
</div>
</Tilt>
)
})
return(
<StackGrid
columnWidth="33.3%"
gutterWidth={20}
gutterHeight={20}
duration={500}
className="stackGrid"
>
{itemList}
</StackGrid>
)
}
}
const mapStateToProps = (state)=>{
return {
items: state.items
}
}
const mapDispatchToProps= (dispatch)=>{
return{
addToCart: (id)=>{dispatch(addToCart(id))}
}
}
export default connect(mapStateToProps,mapDispatchToProps)(Home)
Upvotes: 1
Views: 9775
Reputation: 7545
It is a race condition. It is because the ref
isn't assigning this.inputRange
soon enough before componentDidMount
, so it is undefined
when you try and add event listeners to the input
.
You can try and add conditionals and various strategies, but that isn't the "React" way of doing this. It is no coincidence that the React way is also the most straightforward. Change those event listeners to be a synthetic event that React handles for you, by making it an inline prop
inside the input
element.
Take out the ref
unless you need it for other things and add the event listeners inline.
<input
onMouseDown={this.unlockStartHandler}
onMouseStart={this.unlockStartHandler}
// and so on
/>
React event listener prop names are always the normal JS name with on
appended to the front (and retaining camelCase naming).
Upvotes: 2