Web/React.js

[ React.js / 에러 ] HTML video 엘레먼트 src 변경 시 렌더링 업데이트가 되지 않는 에러.

SHINNJIWOONG 2023. 6. 30. 19:00

사실 에러라고 하기보다는 리액트의 렌더링에 대해 더 명확하게 알지 못해서 벌어진 나의 실수라고 하는 것이 더 정확하지만...

 

에러 상황 :

현재 리액트로 나의 작업물들을 모아둔 아카이빙 웹사이트를 개발하는 중이다. 내가 구현하고자 했던 기능은, 화면 왼편의 프로젝트 리스트 중 하나를 클릭하면, 화면 오른편에 해당하는 프로젝트의 정보를 보여주는 것인데, 이때, 프로젝트의 데이터에 비디오가 있다면 video 태그를 함께 return하여 보여주는 것이었다. 알고리즘을 구상하여 코딩을 진행했고, 잘 동작하는듯 했다.

하지만, 뜻밖의 문제를 직면했는데, 비디오가 없는 프로젝트를 클릭했다가, 다시 비디오가 포함된 프로젝트를 클릭하는 경우에는 제대로 비디오가 보여졌으나, 비디오가 포함된 다른 두 프로젝트를 연속으로 클릭하면, 이전의 프로젝트 비디오에서 이후 프로젝트 비디오로 바뀌지 않는 문제였다. 

 

텍스트나 사진과 같은 요소들은 제대로 변경이 되는데, 유독 비디오의 내용물만 제대로 업데이트가 되지 않았다. 

그렇다면, 이는 알고리즘의 문제는 아닐 것이라고 판단했고, 비디오의 src 속성을 바꾸는 경우에 렌더링이 다시 되지 않는 것이라고 판단하여 구글링을 시작했다. 

 

해결 :

구글링을 하다가 이 포스트를 찾게 되었는데, 아마도 이 글을 쓰신 분도 나와 같은 기능을 구현하려고 했고, 같은 문제에 직면했던 듯 하다.

https://robfarr.me/blog/react-doesnt-update-html5-video-sources/

 

React Doesn't Update HTML5 Video Sources — Rob Farr

React Doesn't Update HTML5 Video SourcesPosted on Wednesday 14th August 2019.I’ve been developing a super simple video player React component lately, based around the HTML5 element. In the development environment provided with create react app the compon

robfarr.me

원인 : 

video 태그 내에 src 속성에 값을 props를 통해서 넘겨주는 경우, 속성의 값만 변경할 뿐, 엘레먼트 전체를 다시 렌더링하지 않는다. 또한, 비디오가 한번 렌더되었을 시에, URL을 바꾼다고 해서 다시 렌더링하지 않는다. 

이는 리액트의 장점에 의한 문제였다. 리액트는 virtual DOM의 활용을 통해서 오직 바뀐 부분만 교체하는 방식으로 렌더링을 진행하는데, 이러한 이유로 src 값만을 교체했을때, 리액트의 입장에서 전체를 다시 렌더링하는 것은 불필요하다고 본다. 

 

해결 방식 :

video 태그의 src를 변경하면서, 리액트한테 '이거 다시 렌더링 해야함'이라고 속여주면 된다. 

video 태그 안에는 key라는 속성이 있는데, 이 속성을 바꾸는 경우에 리액트는 좀 더 호들갑을 떨게 되는 듯 하다. 그리고 리액트는 속성값만 바꾸는 데에 그치지 않고, 엘레먼트 자체를 다시 렌더링 해버린다. 

function VideoPlayer(id, video){
	return(
    	<video key={id} controls>
        	<source src={video} />
    	</video>
    )
};

위의 코드처럼 자체적으로 key 값을 부여하게 되면, key 값이 바뀜에 따라서 리액트의 re-render를 발생시킬 수 있다. 

다행히, 나의 경우에 프로젝트 데이터마다 고유한 인덱스 번호가 있었기 때문에, key 값에 인덱스 번호를 넣어주면 각각 프로젝트마다 다른 값을 부여할 수 있었고, key = {id}를 추가함으로써 간단하게 해결할 수 있었다. 

 

하지만 아직까지 의문인 것은, key값이나 src값이나 같은 property인 것 같은데, 왜 전자는 다시 렌더링하고 후자는 그냥 값만 바꾸고 끝내는지는 모르겠다. 더 알아볼 필요가 있을 듯 하다.