[JS]canvas 1 (with React)
React로 Canvas 사용하기
js를 사용 할 경우 getElementById를 사용하여 캔버스 태그에 접근하지만 react에서는 useRef를 사용하여 접근해야 한다.
1. canvasRef 설정
function Canvas(){
const canvasRef = useRef(null);
return(
<div>
<h2>캔버스</h2>
<canvas ref={canvasRef} width="500" height="500"></canvas>
</div>
)
}
useRef()를 사용하여 Ref객체를 만들고, <canvas>
의 ref로 속성을 지정한다.
이렇게 하면 canvasRef.current 의 값은 <canvas ref={canavasRef}>
를 가르키게 된다.
2. useEffect 사용
function Canvas(){
const canvasRef = useRef(null);
const contextRef = useRef(null);
const [ctx, setCtx] = useState(null);
useEffect(()=>{
const canvas = canvasRef.current;
canvas.width = 500;
canvas.height = 500;
const context = canvas.getContext("2d");
contextRef.current = context;
setCtx(contextRef.current);
},[])
1.<canvas>
컴포넌트가 렌더링 된 시점(mount)을 보장하면서(=mount된 이후) canvas와context를 가져오기 위해 useEffect
를 사용한다.
참고 : useEffect() : 컴포넌트의 렌더링 결과가 실제 돔에 반영된 뒤(componentDidMount)와 컴포넌트가 업데이트된 뒤(componentDidUpdate), 컴포넌트가 사라지기 직전(componentWillUnmount)에 호출된다.
2.useRef()
가 반환한 canvasRef
의 current속성 값을 const변수canvas
에 정의한다. 이제 const변수 canvas
는 조작하려는 <canvas>
를 가리키게 된다.
3.캔버스에 그림을 그리기 위해서 getContext("2d")
메서드로 2d그림을 그릴 수 있게 context
를 정의 한다.
4.contextRef를 useRef를 사용하여 정의한다. contextRef
의 current 어트리뷰트에 3번에서 정의한 context를 대입한다. 이제 contextRef.current를 기준으로 그림을 그리게 된다.
참고 : 어느 분의 블로그에서 봤는데 useState를 사용하지 않고, useRef를 사용한 드로잉 컨텍스트를 참조하여 작동하였더니 render가 될 때 참조하는 값이 가끔
null
이란 오류가 발생한다고 한다. 이 오류를 수정하기 위해 useState를 사용하여 ctx의 state에 드로잉컨텍스트를 할당하여 해결한다.
5.위와 같은 오류를 해결하기위해 useState를 사용하여 ctx에 contextRef.current를 넣어준다.
3. draw함수 정의
function Canvas(){
const canvasRef = useRef(null);
const contextRef = useRef(null);
const [ctx, setCtx] = useState(null);
useEffect(()=>{
const canvas = canvasRef.current;
canvas.width = 500;
canvas.height = 500;
const context = canvas.getContext("2d");
contextRef.current = context;
setCtx(contextRef.current);
},[])
function draw(){
ctx.arc(100,100,50,0,Math.PI*2,false);
ctx.fill();
}
ctx를 사용하여 (100,100)을 중심으로 하고 반지름은 50, 0을 startAngle, Math.PI*2를 endAngle로 두는 호를 그린다.
ctx.fill()
를 사용하여 경로의 내부가 채워진 도형을 그리게 된다.
참고 : arc함수에 각도는 라디안 값을 사용한다. radian = (Math.PI/180)*degrees
4. draw()함수 호출
function Canvas(){
const canvasRef = useRef(null);
const contextRef = useRef(null);
const [ctx, setCtx] = useState(null);
useEffect(()=>{
const canvas = canvasRef.current;
canvas.width = 500;
canvas.height = 500;
const context = canvas.getContext("2d");
contextRef.current = context;
setCtx(contextRef.current);
},[])
function draw(){
ctx.arc(100,100,50,0,Math.PI*2,false);
ctx.fill();
}
if(ctx!=null){
draw();
}
draw함수를 if문으로 둘러싸지 않고 실행시키면
Canvas.js:23 Uncaught TypeError: Cannot read properties of null (reading 'arc')
와 같이 null의 properties를 읽을 수 없다고 하면서 에러가 발생한다.
이는 ctx가 정의되는 useEffect가 실행되기 전에 draw를 호출해서 발생하는 것이다.
위에서 말했다시피 useEffect() 는 컴포넌트의 렌더링 결과가 실제 돔에 반영된 뒤(componentDidMount)와 컴포넌트가 업데이트된 뒤(componentDidUpdate), 컴포넌트가 사라지기 직전(componentWillUnmount)에 호출되기 때문이다.
따라서 if(ctx!=null)
로 조건을 주고 draw함수를 호출해야 한다.
전체코드
function Canvas(){
const canvasRef = useRef(null);
const contextRef = useRef(null);
const [ctx, setCtx] = useState(null);
useEffect(()=>{
const canvas = canvasRef.current;
canvas.width = 500;
canvas.height = 500;
const context = canvas.getContext("2d");
contextRef.current = context;
setCtx(contextRef.current);
},[])
function draw(){
ctx.arc(100,100,50,0,Math.PI*2,false);
ctx.fill();
}
if(ctx!=null){
draw();
}
return(
<div>
<h2>캔버스</h2>
<canvas className="canvas" ref={canvasRef} width="500" height="500"></canvas>
</div>
)
}
export default Canvas
댓글남기기