본문 바로가기
fastcampus

[패스트캠퍼스 수강 후기] 프론트엔드 인강 100% 환급 챌린지 19회차 미션

by 새우하이 2020. 9. 25.

userRef 로 특정 DOM선택

html과 js를 사용할 때는 특정 DOM을 선택해야하는 상황에 getElementById, querySelector 같은 DOM selector 를 사용한다.
React를 사용하는 프로젝트에서도 DOM을 직접 선택해야하는 상황이 발생 할 수 있다.
예를 들어 scrollbar 위치를 가져와서 설정해줘야 하거나 , focus 를 설정해야한다는지 등 다양한 상황들이있다. 추가로 video.js jwplayer같은 html5비디오 관련 라이브러리나 그래프관련 라이브러리 등을 사용할 때도 특정 DOM에 라이브러리를 적용해야 하기 때문에 DOM을 선택해야하는 상황이 발생할 수 있다.

그럴때는 react에서는 ref를 사용하는데 함수형 컴포넌트에서는 useRef라는 hook함수를 사용해서 ref를 사용한다.
class형 컴포넌트에서는 React.createRef 또는 callback 함수로도 사용할 수 있다.

import React,{useState} from 'react';

function InputTest(){
    const [inputs,setInputs] = useState({
        name:'',
        nickname:'',
    });
    const {name,nickname} = inputs;

    const onChange = (e) => {
        const {name,value} = e.target;
        setInputs({
            ...inputs,
            [name]: value,
        });
    }

    const onReset = (e) =>{
        setInputs({
            name:'',
            nickname:'',
        });
    }
    return(
        <div>
            <input name="name" placeholder="이름" onChange={onChange} value={name}/>
            <input name="nickname" placeholder="닉네임" onChange={onChange} value={nickname}/>
            <button onClick={onReset}>초기화</button>
            <div>
                <span>값 : </span>
                {name}({nickname})
            </div>
        </div>
    );
}

export default InputTest;

를 실행해서 초기화버튼을 눌렀을때 react자체 기능으로는 딱히 할 수 있는것이 없다.그래서 DOM에 직접 접근해야 한다.

위의 예제를 그대로 사용한다.

import React,{useState,useRef} from 'react';

useRef를 불러와준다.
그리고

    .
    .
    const nameInput = useRef();
    const {name,nickname} = inputs;
    .
    .

nameInput을 선언해서 useRef()를 담아준다.
nameInput이라는 객체가 만들어지는데
이제 우리가 선택하고 싶은 DOM
<input name="name" placeholder="이름" onChange={onChange} value={name} ref={nameInput}/>
에 ref={nameInput}을 추가해준다
이제 여기에 접근하기 위해서는 onReset에서


    const onReset = (e) =>{
        setInputs({
            name:'',
            nickname:'',
        });
        nameInput.current.focus();
    }

nameInput을 살펴보면 current라는 값이있고 이 값이 해당 돔을 가리키고 있다. 여기서 DOM API 중 focus라는 함수를 호출하면 focus가 해당 input으로 잡히게 된다.

/* InputTest.js */
import React,{useState,useRef} from 'react';

function InputTest(){
    const [inputs,setInputs] = useState({
        name:'',
        nickname:'',
    });
    const nameInput = useRef();
    const {name,nickname} = inputs;

    const onChange = (e) => {
        const {name,value} = e.target;
        setInputs({
            ...inputs,
            [name]: value,
        });
    }

    const onReset = (e) =>{
        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>
                <span>값 : </span>
                {name}({nickname})
            </div>
        </div>
    );
}

export default InputTest;

배열 렌더링하기.

src디렉터리에 UserList.js 라는 컴포넌트를 하나 생성한다.

import React from 'react';

function UserList(){
    const users =[
        {
            id: 1,
            username: 'jiwon',
            email: 'pannchat@likelion.org'
        },
        {
            id: 2,
            username: 'tom',
            email: 'tom@tom.org'
        },
        {
            id: 3,
            username: 'sam',
            email: 'sam@sam.org'
        },
    ];

    return(
        <div>
            <div>
                <b>{users.[0].username}</b><span>({users[0].email})</span>
            </div>
            <div>
                <b>{users.[1].username}</b><span>({users[0].email})</span>
            </div>
            <div>
                <b>{users.[2].username}</b><span>({users[0].email})</span>
            </div>
        </div>
    )
}

export default UserList;

function UserList()를 하나 정의하고
users라는 배열을 하나 생성해준다.

return에는 이 배열의 요소들을 하나하나 렌더링하는 jsx 코드를 작성한다.

이제 App컴포넌트에 렌더링한다.
기존에 사용했던 InputTest를지우고 UserList로 바꾼다.

import React from 'react';
import UserList from './UserList';
function App() {

  return (
    <UserList />
  )
}

export default App;

하지만 이렇게 사용하면 같은 코드를 세번이나 사용하여 렌더링 하게된다.

UserList 컴포넌트에
User라는 컴포넌트를 하나 더 추가해준다.
그리고 user 라는 Props를 추가해준다.

<div>
<b>{user.username}</b><span>({user.email})</span>
</div>

를 추가해준다.

그리고 이 User컴포넌트를
UserList 컴포넌트에 사용해준다.

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: 'jiwon',
            email: 'pannchat@likelion.org'
        },
        {
            id: 2,
            username: 'tom',
            email: 'tom@tom.org'
        },
        {
            id: 3,
            username: 'sam',
            email: 'sam@sam.org'
        },
    ];

    return(
        <div>
            <User user={users[0]} />
            <User user={users[1]} />
            <User user={users[2]} />
        </div>
    )
}

export default UserList;

이렇게 사용하면 배열이 고정적일때 효과적이지만
배열이 늘어나거나 줄어드는 경우에는 javascript 배열의 내장함수 map을 사용해준다.
이 map함수를 사용해서 객체배열 형태로되어있는 배열을 컴포넌트 엘리먼트 형태의 배열로 변환해주면 된다.

사용법은 간단하다 위의 예제에서

.
.
           id: 3,
            username: 'sam',
            email: 'sam@sam.org'
        },
    ];

    return(
        <div>
            {
                users.map(
                    user => (<User user={user}/>) 
                )
            }
        </div>
    )
    .
    .

이 부분만 바꿔주면 같은 결과로 실행되는 것을 확인할 수 있다.
브라우저에서 보면 warning이 뜨는것을 확인할 수 있는데.


각 child가(각 user) key라는 prop이 있어야한다고 경고한다. key는 원소마다 고유값을 줘서 리렌더링 성능을 최적화 해주는것인데. 우리가 작성한 코드에서 배열은 고유값이라고 볼 수 있는 id를 같이 작성해줬다.
이것을 key로 사용한다.

user => (<User user={user} key={user.id}/>) 

이렇게 수정하여 실행시켜 보면 경고가 사라진것을 확인할 수 있다. 하지만 key로 사용할 고유값이 없으면 어떻게 해야할까?

그럴땐 map함수의 두번째 파라미터인 index를 사용한다

(user, index) => (<User user={user} key={index}/>) 

이것은 단순히 경고만 사라지게 할 뿐 성능적으로 이점은 없다.

#key의 역할

const array = ['a','b','c','d'];

이런 배열이 있다고 가정하자.
그리고 이 배열을 div element로 변환해준다고 가정한다.

array.map(item => <div>{item}</div>);

예를들어 b와 c사이에 z가 삽입된다고하면
c를 z로 바꾼뒤 d를 c로바꾸고 뒤에 d를 삽입하게된다.
c,d를 놔두고 z를 삽입만 하면되는데 이런 번거로운 과정을 거치게 되는것이다.
만약 a를 없앤다고하면 a자리에 b가들어가면서 하나씩 대치된다.
이것은 각 배열의 원소가 자신이 몇번째인지만 알고있고 정확히 어떤 값을 렌더링해야하는지 모르기때문이다.

하지만 key가 있으면 렌더링하는 결과물에서 어떤값을 가리키고있는지 알고있기 때문에 z를 추가해도 b와c사이에 z가 삽입되는 형태로 동작한다.

 

해당 내용은 아래 링크에서 수강할 수 있다.

프론트엔드 개발 올인원 패키지 with React Online. 👉https://bit.ly/2ETLEzm

 

프론트엔드 개발 올인원 패키지 with React Online. | 패스트캠퍼스

성인 교육 서비스 기업, 패스트캠퍼스는 개인과 조직의 실질적인 '업(業)'의 성장을 돕고자 모든 종류의 교육 콘텐츠 서비스를 제공하는 대한민국 No. 1 교육 서비스 회사입니다.

www.fastcampus.co.kr

 

댓글