Totally new to react.js and after going through the tutorial and reading the docs, I'm still struggling a bit with using js fetch to load my data from a JSON file as well as setting properties from an array of objects. I'm also not certain I'm accessing DOM properties correctly in my event handler. I must be missing something rather straightforward.
For reference, here's my code with the rest of the project and here's what it's supposed to look like.
ETA: I had no idea from the docs that babel browser was deprecated so decided to just use straight Javascript with ES5 syntax instead of JSX. Code updated below, but it's still not rendering the markup.
var CanvasAnimation = React.createClass({
getInitialState: function() {
return {data: []};
},
loadData: function() {
/*
fetch("data.json")
.then(function(response) {
return response.json
.then(function(json){
this.setState({data: json});
}.bind(this))
}.bind(this));
*/
const data = [
{ id: "stalkerOne", width: 225, height: 434, spriteSheetURL: 'spriteSheets/stalkerone.jpg', rows: 5, columns: 5, totalFrames: 24 },
{ id: "stalkerTwo", width: 175, height: 432, spriteSheetURL: 'spriteSheets/stalkertwo.jpg', rows: 6, columns: 5, totalFrames: 26 },
{ id: "stalkerThree", width: 251, height: 432, spriteSheetURL: 'spriteSheets/stalkerthree.jpg', rows: 6, columns: 5, totalFrames: 28 }
];
},
componentDidMount: function() {
this.loadData();
},
componentDidUpdate: function() {
function animation(json) {
return json.map(function(data) {
return(
new CanvasSprite(
document.getElementById(data.id),
data.width,
data.height,
data.spriteSheetURL,
data.rows,
data.columns,
data.totalFrames)
);
});
};
this.setState({animaton: animation(this.state.data)});
},
handleInteraction: function(event, index) {
var offsetY = event.clientY - event.node.getBoundingClientRect().top;
var relY = offsetY/this.state.data.height;
this.props.animation[index].setFrame(relY);
},
render: function() {
var canvases = this.state.data.map(function(data, index) {
return (
React.createElement('canvas',
id = data.id,
width = data.width,
height = data.height,
style = 'border:5px solid white',
onMouseOver= this.handleInteraction(event, index))
);
});
return(
React.createElement('div', canvases)
);
}
});
ReactDOM.render(
React.createElement(CanvasAnimation, null),
document.getElementById('content')
);
You have tons of syntax errors in your code, I have fixed them for you.
const { Component } = React;
const { render } = ReactDOM;
class CanvasAnimation extends Component {
state = {
data: []
};
loadData() {
function animation(json) {
return json.map(function(data) {
return (
new CanvasSprite(
document.getElementById(data.id),
data.width,
data.height,
data.spriteSheetURL,
data.rows,
data.columns,
data.totalFrames
)
);
});
}
fetch("data.json")
.then(response => response.json())
.then(json => {
console.log(json);
this.setState({
data: json,
animation: animation(json)
});
});
}
componentDidMount() {
this.loadData();
}
handleInteraction(e) {
var offsetY = e.clientY - e.node.getBoundingClientRect().top;
var relY = offsetY/this.state.data.height;
this.props.animation.setFrame(relY);
}
render() {
var canvases = this.state.data.map(function(data) {
return (
<canvas
id={data.id}
width={data.width}
height={data.height}
style={{border: '5px white'}}
onMouseOver={this.handleInteraction}
/>
);
});
return (
<div>{canvases}</div>
);
}
}
render(
<CanvasAnimation />,
content
);
I don't know the response of your API so I'm not sure if there's other to fix.
Some of the problems I have noticed:
Probably your indentation is wrong, because you had functions with double return
statements. I suggest you to enable ESLint in your IDE to catch those errors.
You have not understood how setState
works, you can't just do:
this.setState({
foo: 'bar',
baa: myFn(this.state.foo)
});
Otherwise, this.state.foo
inside myFn
will refer to the old value of it, and not to the new one that you are setting right now.
You'd have to do this.setState({foo: 'bar'}, () => this.setState({baa: myFn(this.state.foo)})
, but then, it's better to do as I did in the code I have fixed above.
Ok... Here's the working project. Got some help from @gumingfeng and @hkal.
Lessons learned:
setState()
inside componentDidUpdate()
triggers an infinite loop so had to set the object array directly and independently from state.Whew, I think that's it. Hope this helps others.
And I would just conclude by saying, give React a try without JSX. It's really not that bad :)
const { Component } = React;
const { render } = ReactDOM;
class CanvasAnimation extends Component {
constructor(){
super();
this.state = {
data: []
};
};
componentDidMount() {
fetch("data.json")
.then( (response) => {
return response.json() })
.then( (json) => {
this.setState({data: json});
});
};
componentDidUpdate() {
function animation(json) {
return json.map( (data) => {
return(
new CanvasSprite(
document.getElementById(data.id),
data.width,
data.height,
data.spriteSheetURL,
data.rows,
data.columns,
data.totalFrames)
);
});
};
//this.setState({animation: animation(this.state.data)}); //causes infinite loop
this.animation = animation(this.state.data);
};
handleInteraction(event, index) {
var offsetY = event.clientY - document.getElementById(this.state.data[index].id).getBoundingClientRect().top;
var relY = offsetY/this.state.data[index].height;
this.animation[index].setFrame(relY);
};
render() {
var canvases = this.state.data.map( (data, index) => {
return (
React.createElement('canvas',
{id : data.id,
width : data.width,
height : data.height,
//style : {border: '5px solid white'},
onMouseMove : (event) => this.handleInteraction(event, index)}
)
);
});
return(
React.createElement('div', null, ...canvases)
);
};
};
render(
React.createElement(CanvasAnimation, null),
document.getElementById('content')
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With