For loop inside Render()
The loop gets called each time the component re-renders, it's a 1280
pushes to an array and that can be a performance issue, you can set it in componentDidMount
or even outside the class since it's not dependent on its data,
Consider Array.from to create and fill the array without creating an intermediate one.
const range = Array.from({length: 1280}, (_, i) => i);
And since you're filling it with int
s and the select
value is an int
you don't really need parseInt
.
Using document.querySelector
to read values
Basically, you can't easily rely on the input field because the state needs to come from the React app's state, not from the browser's idea of what the value should be.
See more explanation in this blog post.
You should instead use the state to store the values of the inputs. ( see code snippet below )
Accessing the DOM using document.querySelector
In React, we do not directly manipulate the actual DOM. Instead, we must manipulate the virtual representation and let React take care of changing the browser's DOM.
Check this article for in depth explanation and this one for different ways to access the DOM.
using refs
, instead of doing document.querySelector('video')
, you can add a ref
like : <video src={video} controls ref={video => this.video = video}/>
then use this.video
to do what you would do with a regular html element.
import React, { Component } from 'react';
import './App.css';
import video from './video.mp4';
import watermark from './watermark.png';
const range = Array.from({ length: 1280 }, (_, i) => i);
class App extends Component {
constructor() {
super();
this.state = {
select: 0,
live: false,
positionX: 0,
positionY: 0,
checked: false
};
}
componentDidMount() {
const context = this.canvas1.getContext('2d');
context.drawImage(this.video, 0, 0, 720, 1280);
context.drawImage(this.watermark, this.state.select, this.state.select);
if (this.state.live) {
this.setState({ image: canvas.toDataURL() });
}
}
render() {
return (
<div className="app">
<video src={video} controls ref={video => this.video = video} />
<div>
<div className="watermarkButton" style={{}}>
<span className="watermarkButtonX">Watermark X
<select
className="positionX"
onChange={value => this.setState({ select: value, positionX: value })}
value={this.state.positionX}>
{range.map(i => (
<option key={i} value={i}>{i}</option>
))}
</select>
</span>
<span className="watermarkButtonY">Watermark Y
<select
className="positionY"
onChange={value => this.setState({ select: value, positionY: value })}
value={this.state.positionY}>
>
{range.map(i => (
<option key={i} value={i}>{i}</option>
))}
</select>
</span>
<span>Live</span>
<input
type="checkbox"
name="live"
value={this.state.live}
onChange={e => this.setState({ live: e.target.value })}
/>
</div>
<button className="watermarkButton watermarkSubmit"
onClick={() => {
const context = this.canvas2.getContext('2d');
context.drawImage(this.video, 0, 0, 1280, 720);
context.drawImage(this.watermark, this.state.positionX, this.state.positionY);
this.setState({ image: canvas.toDataURL() });
}}> Watermark! </button>
<canvas ref={canvas => this.canvas1 = canvas} width={1280} height={720} />
<canvas ref={canvas => this.canvas2 = canvas} width={1280} height={720} />
<img
alt="watermarks"
className="watermark"
src={watermark}
style={{ visibility: 'visible' }}
ref={watermark => this.watermark = watermark}
/>
<img
alt="watermarks"
className="imageDisplay"
height="405px"
width="560px"
src={this.state.image}
/>
</div>
</div>
);
}
}
export default App;