1주차 - 자바스크립트 기초(1) 강의에서 이 기능을 구현했었는데, 이번 시간에는 Ref를 사용해서 리액트 요소를 가져올 것이다. 자바스크립트에서는 진짜돔을 수정하는 방식이지만 리액트 요소에 추가된 input은 가상돔 내에서 일어나는 작업이기 때문에 오류가 나기 때문이다.
App.js
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
list: ["Eternals", "First Cow", "Seberg", "French Dispatch"],
};
this.text = React.createRef();
}
render() {
return (
<div className="App">
<Container>
<Title>개봉예정작</Title>
<Line/>
<BucketList list={this.state.list}/>
</Container>
<div>
<input type="text" ref={this.text}/>
</div>
</div>
);
}
}
➊
<input type="text"/>
텍스트를 가져오기 위해서render
안에 input을 생성한다.➋
this.text = React.createRef();
constructor
안에 Ref를 선언한다. Ref는 '이름표'같은 개념이다.➌
<input type="text" ref={this.text}/>
<input type="text"/>
에 ➋에서 선언한 Ref를 적용한다.
componentDidMount()
에서 console.log(this.text);
을 찍어 확인하면 current 안에 input이 들어간 것을 확인할 수 있다. 이처럼 리액트에서는 Ref를 생성하면 콘솔 출력시 current:(Ref로 달아준 돔 요소)
로 나타난다.
이번 강의에서는 input의 value를 가져와야하므로console.log(this.text.current.value);
로 다시 찍어준다. 이 상태에서 input에 텍스트를 입력한다고 해도 콘솔창에는 아무것도 출력이 되지 않는다. componentDidMount()
안에 적었기 때문이다.
그러나 render
에서 찍으면 Uncaught TypeError: Cannot read properties of null (reading 'value') 라는 에러가 난다. this.text.current
를 null로 인식하기 때문이다. 결국 가상돔과 진짜돔의 문제인데, 가상돔의 Render 처리과정에서 요소를 만들고 있을 때에 진짜돔에서는 해당요소가 없기 때문에 이런 에러가 난 것이다.
이러한 이유로 value를 확인하기 위해선 다른 방법이 필요하다.
onChange
<div> <input type="text" ref={this.text} onChange={() => { console.log(this.text.current.value); }}/> </div>
input의 속성 중 하나인
onChange
는 input의 입력값이 변하면onChange
에 넣은 함수가 호출된다. 즉, input을 입력하지 않은 상태에서는 함수가 실행되지 않는다. 그래서render
에 입력했음에도 불구하고 콘솔창 실행시 오류가 나질 않는 것이다.input에 텍스트를 입력해서 함수가 호출됐을 시점엔 이미 render - componentDid-Mount 처리과정을 마친 상태이기 때문에 돔 요소를 찾을 수 있다.
onChange
에 속한 화살표 함수가 실행될 무렵에는this.text.current
에 이미 input이 들어가 있기 때문에 오류가 나지 않는다.
BucketList.js
const BucketList = ({ list }) => {
const my_lists = list;
const my_wrap = React.useRef(null);
console.log(my_wrap);
return (
<div ref={my_wrap}>
.
.
.
);
}
➊
const my_wrap = React.useRef(null);
클래스형 컴포넌트와 마찬가지로 어떤 요소에 Ref를 넣어줄 것인지 정한다음 변수를 생성한다. 함수형 컴포넌트에서는 Lifecycle Method를 쓸 수 없다. 즉,constructor
안에서 초기화 작업을 해줄 수 없기 때문에 React Hooks인 React.useRef() 를 사용한다. 파라미터로 넘겨주는(null)
은 초기화 해줄 값을 말한다.➋
<div ref={my_wrap}>
return
의<div>
에 ➊에서 선언한 변수를 넣어준다.➌
console.log(my_wrap);
콘솔창에서 확인하면{current: null}
이라고 찍히는데, ➊에서 넘겨준 초기값으로 다른 값을 설정한다면 그 값으로 찍힌다.
current
에 div
가 아니라 (null)
이 뜨는 이유는 return
되기 전에 console.log(my_wrap);
을 먼저 작성했기 때문이다.
div
를 확인하기 위해선 약간의 꼼수가 필요하다.
window.setTimeout
window.setTimeout(() => { console.log(my_wrap); }, 1000);
window.setTimeout(() => {}, 1000);
두번째 인자만큼의 시간(ms 기준)이 흐른 후에 첫번째 인자를 실행해주는 함수.
위 코드에선 1초가 흐른 후에console.log(my_wrap);
이 실행되도록 설정하였다. 1초 사이에 가상돔에서return
한 요소들을 진짜돔으로 보내 버리기 때문에 콘솔창에서div
를 확인할 수 있다.