React 주말 #6
#6 침대에서 뒹글
useRef 로 특정 DOM 선택
자바스크립트에서는 우리가 특정 DOM을 선택해야할 때, getElementById, querySelector 같은 DOM selector 함수를 사용해야한다.
리액트에서 가끔식 DOM을 직접 선택해야 하는 상황이 올 수 있다.
이 때, 리액트에서 ref라는 것을 사용한다.
함수형 컴포넌트에서 ref 를 사용 할 때에는 useRef 라는 Hook 함수를 사용한다.
클래스형 컴포넌트에서는 우리가 콜백 함수를 사용하거나 React.createRef 라는 함수를 사용하는데 현재는 중요하지 않는다.
전에 만든 InputSample 초기화 버튼을 클릭했을 때 이름 input 에 포커스가 잡히도록 useRef 를 사용하여 기능을 구현하겠다!
InputSample.js
import React, { useState, useRef } from 'react';
function InputSample() {
const [inputs, setInputs] = useState({
name: '',
nickname: ''
});
const nameInput = useRef();
const { name, nickname } = inputs; // 비구조화 할당을 통해 값 추출
const onChange = e => {
const { value, name } = e.target; // 우선 e.target 에서 name 과 value 를 추출
setInputs({
...inputs, // 기존의 input 객체를 복사한 뒤
[name]: value // name 키를 가진 값을 value 로 설정
});
};
const onReset = () => {
setInputs({
name: '',
nickname: ''
});
nameInput.current.focus();
};
return (
<div>
<input
name="name"
placeholder="이름"
onChange={onChange}
value={name}
ref={nameInput}
/>
<input
name="nickname"
placeholder="닉네임"
onChange={onChange}
value={nickname}
/>
<button onClick={onReset}>초기화</button>
<div>
<b>값: </b>
{name} ({nickname})
</div>
</div>
);
}
export default InputSample;
useRef() 를 사용하여 Ref 객체를 만들어주고, 이 객체를 우리가 선택하고 싶은 DOM 에 ref 값으로 설정해야한다.
이 때, Ref 객체의 .current 값은 우리가 원하는 DOM 을 가르킨다.
위의 코드에서 onReset 함수에서 input에 포커스를 하는 focus( ) API를 호출해줬다.
nameInput.current.focus();
결과는...
초기화를 눌렀을 때, 이름 input 태그에 focus가 들어온다.
그리고
const refContainer = useRef(initialValue);
useRef는 .current 프로퍼티로 전달된 인자(initialValue)로 초기화된 변경 가능한 ref 객체를 반환한다.
배열 렌더링하기
이번에는 리액트에서 객체가 아닌 배열을 렌더링하는 방법을 알아보겠다.
const users = [
{
id: 1,
username: 'velopert',
email: '[email protected]'
},
{
id: 2,
username: 'tester',
email: '[email protected]'
},
{
id: 3,
username: 'liz',
email: '[email protected]'
}
];
이렇게 배열이 존재한다고 가정해보자!
어떻게하면은 이 배열을 컴포넌트로 렌더링할 수 있을까?
그냥 코드 그대로 작성을 하면되는데, 우리는 src 폴더에 UserList라는 파일을 생성해서 다음과 같이 컴포넌트를 생성한다.
UserList.js
import React from 'react';
function UserList() {
const users = [
{
id: 1,
username: 'velopert',
email: '[email protected]'
},
{
id: 2,
username: 'tester',
email: '[email protected]'
},
{
id: 3,
username: 'liz',
email: '[email protected]'
}
];
return (
<div>
<div>
<b>{users[0].username}</b> <span>({users[0].email})</span>
</div>
<div>
<b>{users[1].username}</b> <span>({users[1].email})</span>
</div>
<div>
<b>{users[2].username}</b> <span>({users[1].email})</span>
</div>
</div>
);
}
export default UserList;
위에처럼 코드를 작성해봤는데, 다시 사용하는 코드를 일일히 넣는건 비효율적이라 컴포넌트를 재사용 할 수 있도록 새로 만들어보겠다.
UserList 파일을 다시 수정해주면...
아! 그리고 한 파일에 하나의 컴포넌트가 아니라 여러개의 컴포넌트를 선언해도 아무런 문제는 없다!
UserList.js
import React from 'react';
function User({ user }) {
return (
<div>
<b>{user.username}</b> <span>({user.email})</span>
</div>
);
}
function UserList() {
const users = [
{
id: 1,
username: 'velopert',
email: '[email protected]'
},
{
id: 2,
username: 'tester',
email: '[email protected]'
},
{
id: 3,
username: 'liz',
email: '[email protected]'
}
];
return (
<div>
<User user={users[0]} />
<User user={users[1]} />
<User user={users[2]} />
</div>
);
}
export default UserList;
이제 컴포넌트를 App 파일에서 렌더링해보겠다.
App.js
import React from 'react';
import UserList from './UserList';
function App() {
return (
<UserList />
);
}
export default App;
결과는...
만약 배열이 100개 이상이면 하나하나 조회해가면서 렌더링하는 방법은 비효율적이라 이럴 때, 자바스크립트 배열의 내장함수인 map( )을 사용하면된다.
map() 함수는 배열안에 있는 각 요소를 변환하여 새로운 배열을 만들어준다.
리액트에서는 동적인 배열을 렌더링을 할 때는 map 함수를 사용하여 일반 데이터 배열을 리액트 엘리먼트로 이루어진 배열로 바꿔준다.
UserList 컴포넌트를 다음과 같이 수정해본다.
UserList.js
import React from 'react';
function User({ user }) {
return (
<div>
<b>{user.username}</b> <span>({user.email})</span>
</div>
);
}
function UserList() {
const users = [
{
id: 1,
username: 'velopert',
email: '[email protected]'
},
{
id: 2,
username: 'tester',
email: '[email protected]'
},
{
id: 3,
username: 'liz',
email: '[email protected]'
}
];
return (
<div>
{users.map(user => (
<User user={user} />
))}
</div>
);
}
export default UserList;
이렇게 작성하면 일일히 각 배열의 요소를 반복해가면서 쓰는게 아니라 한 번만 map 함수를 쓰면 모든 요소가 렌더링된다.
하지만 브라우저의 콘솔로 가보면 특정 에러가 보일 것 이다.
리액트에서는 배열을 렌더링할 때, key라는 props를 설정해줘야한다.
key 값은 각 요소들의 고유값을 설정해야 해서 위의 같은 경우에는 id가 고유 값이다.
key prop을 추가하면...
UserList.js
return (
<div>
{users.map(user => (
<User user={user} key={user.id} />
))}
</div>
);
만약에 배열안에 고유값이 없다면, map 함수를 사용할 때 설정하는 콜백함수의 두 번째 파라미터인 index를 key로 설정해둬된다.
<div>
{users.map((user, index) => (
<User user={user} key={index} />
))}
</div>
여기서 정리하자면...
map 함수에서 key가 필요한 이유는
- Map에 key 값이없다면 중간의 값이 바뀌었을때 그 하위 값들이 전부 변하기 때문인다. key값을 사용한다면 key를 이용해 중간의 값을 추가하게 된다.
참고 : 벨로퍼트와 함께하는 모던 리액트
느낀점 :
- 오늘은 useRef와 배열을 렌더링에 대해 알아보는 시간을 가졌습니다.
- map 함수는 배열를 새롭게 리턴하기 때문에, 리액트에서 많이 사용되고 있고, useRef는 아직 헷갈리는 부분이 있을 수 있어서 다시 공부해야겠다.
Author And Source
이 문제에 관하여(React 주말 #6), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@klucas/React-주말-6저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)