useRef는 리액트의 훅(Hook)중 하나로
변수를 유지하지만 컴포넌트가 리렌더링될 때 값이 초기화되지 않도록 하는 역할을 한다.
const fileInputRef = useRef(null); // handleImageChange 생략 <input type="file" ref={fileInputRef} name="image" accept="image/*" multiple onChange={handleImageChange} style={{ display: 'none' }} /> <button type="button" onClick={() => fileInputRef.current && fileInputRef.current.click()}> 파일 선택 </button>
위 코드에서 useRef는 fileInputRef를 생성하고
<input type = "file" /> 요소의 참조 (reference) 역할을 한다.
즉, fileInputRef.current에는 해당 <input> 요소가 직접 저장된다.
const fileInputRef = useRef(null);
▲ fileInputRef라는 변수를 useRef(null)로 초기화하고
이 변수는 렌더링이 다시 일어나도 값이 유지된다.
<input type="file" ref={fileInputRef} name="image" accept="image/*" multiple onChange={handleImageChange} style={{display:'none'}} />
▲ <input> 태그에 ref={fileInputRef}를 설정하여
이 요소를 직접 참조할 수 있도록 만든다.
<button type="button onClick={() => fileInputRef.current && fileInputRef.current.click()}> 파일 선택 </button>
▲ 파일 선택 버튼을 클릭하면 fileInputRef.current.click()이 실행되는데
이는 <input type="file" /> 요소의 click() 메소드를 호출하는 것이다.
즉, 보이지 않는 파일 선택창을 버튼을 눌렀을 때 강제로 열리게 만든다.
currnt? click() 메소드? 보이지않는 파일 선택창을 왜 강제로 열어?
무슨 말인지 이해가 안간다면, 우선 inpu 태그 안에 style={{ display: 'none'}} 코드를 보면된다.
<input type="file" /> 요소는 지금 display none으로 숨겨져있는데
즉 사용자는 보이지 않는 input을 직접 클릭할 수 없다.
하지만 button을 클릭하면 fileInputRef.current.click()이 실행되면서
파일 업로드 창이 나타난다. 그이유는 click() 메소드 때문이다.
※ click() 메소드 - HTML 요소를 프로그래밍적으로 클릭하는 메소드
=> 일반적으로 버튼을 클릭하면 그 버튼에 연결된 onClick 이벤트가 실행되는데
자바스크립트에서 element.click()을 호출하면
실제 클릭하지 않아도 해당 요소를 클릭한 것과 같은 효과를 줄 수 있다.
만약 click() 메소드가 없다면 버튼을 클릭해도 아무일도 일어나지 않을 것이다.
왜냐하면 파일 선택창을 여는 것은 <input type="file" />이 클릭될 때만 가능하기 때문이며
즉 click()을 사용해서 직접 보이지 않는 <input>을 클릭하도록 속여,
display none으로 숨겨진 input을 대신 클릭하는 방식이 필요하기에 사용한다.
하지만 중요한건 current
current는 무엇이며 useRef의 기본 프로퍼티인가 싶을텐데
그 생각이 맞다. current는 useRef가 반환하는 객체의 정해진 프로퍼티이다.
const fileInputRef = useRef(null);
▲ useRef를 호출하면 { current : 초기값 } 형태의 객체를 반환하며
위 코드에서는 { current :null }이 저장된다.
만약 <input>에 ref를 연결하면
current 값이 해당 DOM 요소로 업데이트된다. ▼
<input type="file" ref={fileInputRef} />
이후 fileInputRef.current를 확인해보면,
console.log(fileInputRef.current) // <input type="file"> 요소가 출력됨
즉, current는 useRef가 제공하는 고정된 프로퍼티로,
해당 ref가 가리키는 값을 저장하는 역할을 한다.
current는 직접 수정할 수도 있다?
useRef는 일반적인 상태(state) 처럼 동작하지 않는다.
current 값을 직접 변경해도 컴포넌트가 다시 렌더링되지 않는다.
fileInputRef.current = "Hello"; console.log(fileInputRef.current); // "Hello"
이처럼 current는 그냥 객체의 속성처럼 자유롭게 수정할 수 있는 값이다.
정리하자면.. useRef는 컴포넌트가 다시 렌더링되더라도 유지해야하지만
화면에 영향을 주지 않는 값을 저장할 때사용된다.
위 파일 등록하는 로직에서의 useRef는
파일 선택을 클릭하면 fileInputRef.current.click()이 실행되어
파일 선택창이 열릴때 사용자가 파일을 선택하면 <input type="file">의 onChange 이벤트가 발생하여
선택한 파일이 처리되고 이 과정에서 컴포넌트는 리렌더링이 되지 않기에 useRef를 사용하는 것이다.
만약에 useState를 사용했다면?
const [selectedFile, setSelectedFile] = useState(null); const handleImageChange = (event) => { setSelectedFile(event.target.files[0]); // 선택한 파일을 상태로 저장 }; <input type="file" onChange={handleImageChange} />
위와같이 useState를 사용했다면 setSelectedFile이 실행되면
컴포넌트가 리렌더링이 되어 상태가 업데이트 되면서 화면이 다시 그려지게되므로
파일을 업로드할 수 없게된다.
그러므로 useRef를 사용하면 current에 파일 정보를 저장할 수 있어서
리렌더링 없이 파일을 선택하고 업로드 할 수 있는 것이다.
'React' 카테고리의 다른 글
JavaScript / React - IntersectionObserver (0) | 2025.03.28 |
---|---|
React- React에서 인라인 스타일 사용하기 (0) | 2025.02.28 |
React - React의 렌더링 방식 : State (0) | 2025.02.27 |
React - State (0) | 2025.02.26 |
React - children props (0) | 2025.02.21 |