React

벨로퍼트 React 내용 정리 (1장 10~15)

Yujzu 2023. 8. 18. 17:59

출처: https://react.vlpt.us/basic/

 

1. useRef로 특정 DOM 선택하기

- 배경 : 리액트에서도 특정 DOM 을 직접 선택해야 하는 상황이 발생할 수 있다. 

 ex. 특정 엘리먼트의 크기를 가져오기, 스크롤바 위치 가져오기, 포커스 설정하기, 그래프 관련 라이브러리 등의 외부 라이브러리 사용시 특정 DOM에 적용하기 위해 DOM을 선택할 때

 

- 예시 : 초기화 버튼을 클릭했을 때 포커스가 초기화 버튼에 그대로 남아있지 않고 이름 input 에 포커스가 잡히도록 하기

 

- 사용방법 : useRef() Hook 함수를 사용하여 Ref 객체를 만들고, 이 객체를 선택하고 싶은 DOM 에 ref 값으로 설정해주면, Ref 객체의 .current 값은 우리가 원하는 DOM 을 가르키게 된다.

예시에서는 onReset 함수에서 input 에 포커스를 하는 focus() DOM API 를 호출해주었다.

 

예시 1)

function InputSample() {

  const nameInput = useRef();
 // const nameInput = useRef<HTMLInputElement | null>(null); // Typescript
  
  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;

예시 2)

  const downloadRef = useRef<HTMLImageElement>(null);
  
    const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);

    const popper = usePopper(downloadRef.current, popperElement, {
    placement: 'bottom-end',
  }); // usePopper 훅을 사용하여 팝오버(Popover)나 툴팁(Tooltip)과 같은 UI 요소의 위치를 계산하고 관리

	<DownloadPeriod
              src={calImg}
              ref={downloadRef}
              onClick={onClickHandler}
    />

 

2. 배열 렌더링

map() 으로 동적인 배열을 렌더링 할 때 key를 삽입하는 이유는?

key가 없을 시 : 배열이 변경될 시에 변경 된 순서에 따라 다음 모든 요소가 변경됨

key가 있을 시 : 배열 업데이트 시 수정되지 않는 기존의 값은 그대로 두고 원하는 곳에 내용을 삽입하거나 삭제

 

3. useRef로 컴포넌트 안의 변수 만들기

useRef Hook 의 DOM 을 선택하는 용도 외에 다른 용도는!

=> 컴포넌트 안에서 조회 및 수정 할 수 있는 변수를 관리하는 것

 

배경 : useRef 로 관리하는 변수는 값이 바뀐다고 해서 컴포넌트가 리렌더링되지 않고, 설정 후 바로 조회 할 수 있다.

이 변수를 사용하여 다음과 같은 값을 관리 할 수 있다.

  • setTimeout, setInterval 을 통해서 만들어진 id
  • 외부 라이브러리를 사용하여 생성된 인스턴스
  • scroll 위치

예시 : 배열에 추가한 새 항목에서 사용 할 고유 id 를 관리하는 용도로  useRef 를 사용하기

 

3-1. 배열에 항목 추가하기

불변성을 지키면서 배열에 새 항목을 추가하는 방법 (push, splice, sort X)

1. spread 연산자 사용

2. concat 함수 사용

 

3-2. 배열에 항목 제거하기

불변성을 지키면서 특정 원소를 배열에서 제거하기 위해서는 특정 조건에 만족하는 원소들만 추출하여 새로운 배열을 만드는 filter 배열 내장 함수를 사용한다.

 

3-3. 배열에 항목 수정하기

예시 : 계정명을 클릭했을때 색상이 초록색으로 바뀌고, 다시 누르면 검정색으로 바뀌도록 onToggle 함수를 구현

배열의 불변성을 유지하면서 배열을 업데이트 할 때 map 함수를 사용한다.

id 값을 비교해서 id 가 다르다면 그대로 두고, 같다면 active 값을 반전시키도록 구현을 한다.

function App() {
const [users, setUsers] = useState([
    {
      id: 1,
      username: 'velopert',
      email: 'public.velopert@gmail.com'
      active: true

    },
    {
      id: 2,
      username: 'tester',
      email: 'tester@example.com'
      active: false
    },
    {
      id: 3,
      username: 'liz',
      email: 'liz@example.com'
      active: false
    }
  ]);
  
  const nextId = useRef(4); // useRef() 를 사용하여 nextId 라는 변수 생성
  // useRef() 안에 파라미터를 넣어주면, 이 값이 .current 값의 기본값이 된다.
  // 이 값을 수정 할때에는 .current 값을 수정하면 되고 조회 할 때에는 .current 를 조회하면 된다.

// 3-1. 배열 추가
  const onCreate = () => {
     const user = {  // 배열에 추가할 새 항목 생성
      id: nextId.current,
      username,
      email
    };
    
    // 배열에 새 항목 추가하는 방법 2가지
    // 1. spread 연산자 사용
    setUsers([...users, user]);
    // 2. concat 메서드 사용
    setUsers(users.concat(user));

	// input 박스 초기화
    setInputs({
      username: '',
      email: ''
    });
	
    // 다음 요소를 위해 id 값 변경
    nextId.current += 1;
  };
  
  // 3-2. 배열 제거
   const onRemove = id => {
    // user.id 가 파라미터로 일치하지 않는 원소만 추출해서 새로운 배열을 만듬
    // = user.id 가 id 인 것을 제거함
    setUsers(users.filter(user => user.id !== id));
  };
  
  // 3-3. 배열 수정
  const onToggle = id => {
    setUsers(
      users.map(user =>
        user.id === id ? { ...user, active: !user.active } : user
      )
    );
  };
  
  return <UserList users={users} onRemove={onRemove} onToggle={onToggle} />; // 배열을 App 에서 선언하고 UserList 에게 props로 전달 
}
function User({ user, onRemove, onToggle }) {
  return (
    <div>
      <b style={{
          cursor: 'pointer',  	// 마우스를 올렸을때 커서가 손가락 모양으로 변경
          color: user.active ? 'green' : 'black' 	// active 값에 따라 폰트의 색상 변경
        }}
         onClick={() => onToggle(user.id)}
        >
        {user.username}
      </b> 
      <span>({user.email})</span>
      <button onClick={() => onRemove(user.id)}>삭제</button>
    </div>
  );
}

function UserList({ users, onRemove, onToggle }) {
  return (
    <div>
      {users.map(user => (
        <User user={user} key={user.id} onRemove={onRemove} onToggle={onToggle} />
      ))}
    </div>
  );
}

export default UserList;