Ryan King Ryan King - 6 months ago 33
Javascript Question

React-ClickDrag Child Component Callbacks

I have react svg component that has 2 children that use react-clickdrag

I'm trying pass a callback function from the parent to child components to be called on drag. The callback function is called as expected on drag but the

this
variable returns the child component rather than the parent component in the callback function.

Have I structured something incorrectly? Or is react-clickdrag modifying the
this
variable somehow?




Parent Component:

import React from 'react';
import Bar from './Bar.jsx';
import Node from './Node.jsx';

class TimeSpan extends React.Component {

constructor(props) {
super(props);
this.state = {
xPos: this.props.xPos,
yPos: this.props.yPos,
length: this.props.length
};
}

changeStartPos(diffPos) {
console.log(this); //returns child component
this.setState({xPos: this.state.xPos + diffPos, length: this.state.length + diffPos});
}

changeEndPos(diffPos) {
console.log(this); //returns child component
this.setState({length: this.state.length + diffPos});
}

render() {
return (
<g>
<Node changePos={this.changeStartPos} xPos={this.state.xPos} yPos={this.state.yPos} radius={10} />
<Node changePos={this.changeEndPos} xPos={this.state.xPos + this.state.length} yPos={this.state.yPos} radius={10} />
</g>
);
}

}

export default TimeSpan;





Child Component:

import React from 'react';
import clickDrag from 'react-clickdrag';

class NodeComponent extends React.Component {

constructor(props) {
super(props);
this.state = {
lastPositionX: 0,
lastPositionY: 0,
currentX: this.props.xPos,
currentY: this.props.yPos
};
}

componentWillReceiveProps(nextProps) {
if(nextProps.dataDrag.isMoving) {
this.props.changePos(nextProps.dataDrag.moveDeltaX);
}
}

render() {
return (
<circle cx={this.props.xPos} cy={this.props.yPos} r={this.props.radius} fill="black" />
);
}

}

var Node = clickDrag(NodeComponent, {touch: true});

export default Node;





index:

import React from 'react';
import {render} from 'react-dom';
import TimeSpan from './TimeSpan.jsx';

class App extends React.Component {
render () {
return (
<svg style={{postion:'fixed', top: 0, left: 0, width: '100%', height: '100%'}}>
<TimeSpan xPos={300} yPos={300} length={300} />
</svg>
);
}
}

render(<App/>, $('#app')[0]);





<html>
<head>
<meta charset="utf-8">
<title>React.js using NPM, Babel6 and Webpack</title>
<script src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
<style>
html, body { margin:0; padding:0; overflow:hidden }
</style>
</head>
<body>
<div id="app" />
<script src="public/bundle.js" type="text/javascript"></script>
</body>
</html>

Answer

With the ES6 syntax your functions will not be bound automatically like they are when you use React.createClass so you'll have to explicitly bind them.

The best place to do this is in the constructor so it only happens once.

constructor(props) {
    super(props);
    this.changeStartPos = this.changeStartPos.bind(this);
    ...
}
Comments