본문 바로가기

WINK-(Web & App)/React.js 스터디

[2024 여름방학 React.js 스터디] 이종윤 #4주차

반응형

useRef

: useRef는 리액트 훅의 한 종류로, Ref는 reference(참조)의 줄임말이다. 

- useRef를 이용하면 특정한 DOM요소에 접근이 가능하면, 불필요한 재렌더링을 하지 않는다는 장점이 있다.

const 변수명 = useRef(초기값)

 

useRef는 변수명에 초기값을 적는 식으로 만든다.

이러한 결과값으로, {current:  초기값}  을 지닌 객체가 반환된다.

useRef에서 기억할 것은 이러한 current라는 키값을 지닌 프로퍼티가 생성되고, 값에 어떤 변경을 줄때도 이 current를 이용해서 한다는 점이다.

<input ref= {변수명}/>

 

그리고 이렇게 반환할 수 있다.

useRef() 를 사용 할 때 파라미터를 넣어주면, 이 값이 .current 값의 기본값이 된다.

그리고 이 값을 수정 할때에는 .current 값을 수정하면 되고 조회 할 때에는 .current 를 조회하면 된다.

 

useRef를 쓰는 이유는 반환된 useRef 객체는 컴포넌트의 전생애주기를 통해 유지가 된다. 

(= 컴포넌트가 계속해서 렌더링이 되어도 컴포넌트가 언마운드되기 전까지는 값을 그대로 유지할 수 있다)

(= currnet 속성은 값을 변경해도 상태를 변경할 때 처럼 React 컴포넌트가 재렌더링 되지 않는다. )

 

-> 자주 변경되는 값을 state에 담으면, 변경될때마다 재렌더링이 일어나서 성능에 안좋은 영향을 미친다.

하지만 useRef를 이용하면 값이 변경될때마다 렌더링이 일어나지 않는다.

map

: 배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 새로운 배열을 반환하는 함수이다.

- 어떠한 배열을 랜더링 하기 위해서는 코드를 그대로 작성해도 되지만 그러면 별로 효율적이지가 않다. 그래서 map 함수를 사용한다.

arr.map(function(currentValue[, index[, array]]) {
    // 변환(mapping)할 로직: 변환된 결과를 반환해야 합니다.
}[, thisArg]);

(* arr: 함수에 적용할 배열이다.)

function arr 배열의 각 요소에 적용할 때 호출되는 콜백 함수입니다. 이 함수는 세 개의 매개변수를 가질 수 있습니다.
  • currentValue (필수): 처리할 현재 요소. 이 매개변수를 통해 현재 요소에 접근할 수 있습니다.
  • index (옵션): 처리할 현재 요소의 인덱스. 이 매개변수를 사용하여 현재 요소의 인덱스에 접근할 수 있습니다.
  • array (옵션): map() 함수를 호출한 배열. 이 매개변수를 사용하여 원본 배열에 접근할 수 있습니다.
thisArg 옵션.
function을 실행할 때 this로 사용할 객체. 이 매개변수는 필요에 따라 사용됩니다.

key 의 중요성

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

이러한 배열이 있다고 가정하자.

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

 

위 배열을 이렇게 랜더링 하자.

 

위 배열의 b 와 c 사이에 z 를 삽입하게 된다면, 리렌더링을 하게 될 때 <div>b</div>  <div>c</div> 사이에 새 div 태그를 삽입을 하게 되는 것이 아니라, 기존의 c 가 z 로바뀌고, d 는 c 로 바뀌고, 맨 마지막에 d 가 새로 삽입된다.

 

그 다음에 a 를 제거하게 된다면, 기존의 a 가 b 로 바뀌고, b 는 z 로 바뀌고, z는 c로 바뀌고, c는 d 로바뀌고, 맨 마지막에 있는 d 가 제거된다.

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

하지만 이렇게 키값을 객체로 하고 이렇게 업데이트 될 때는 배열이 업데이트 될 떄 key 가 없을 때 처럼 비효율적으로 업데이트 하는 것이 아니라, 수정되지 않는 기존의 값은 그대로 두고 원하는 곳에 내용을 삽입하거나 삭제한다.

spread 연산자

: ES6부터는 배열을 합칠 때 spread 또는 전개 연산자라고 불리는 ... 기호가 많이 사용되는데 배열을 나타내는 [] 기호 안에서 어떤 원소 앞에 ... 기호를 붙이면 그 배열 내의 원소가 마치 펼쳐진 것처럼 해당 배열에 추가된다.

const numbers = [1, 2, 3];
const letters = ["A", "B"];
const spread = [...numbers, ...letters];
console.log(spread); // [1, 2, 3, 'A', 'B']

concat()메서드

: 연결하다(concatenate)를 의미하는 배열의 concat() 메서드를 사용하면 하나의 배열에 다른 배열을 합칠 수 있다.

const numbers = [1, 2, 3];
const letters = ["A", "B"];
const concatenated = numbers.concat(letters);
console.log(concatenated); // [1, 2, 3, 'A', 'B']

onRemove()함수

: 우선 이 함수는 id가 ~인 함수를 삭제시키는 기능을 가지고있다.

어떠한 값을 지우라는 이벤트가 발생하면

 <UserList users={users} onRemove={onRemove} />

이렇게 지우면 된다.

 

참고로 onClick={onRemove(id)} 이런 식으로 코드를 작성하면 절대 안 된다. 이렇게 하면 컴포넌트가 렌더링 될 때 바로 모든 객체들이 삭제될 것입니다. 렌더링 됨과 동시에 onRemove() 함수를 실행하기 때문이다. 

그래서 보통 onClick = {onRemove}으로 지정해서 ()를 제외하는 방법으로 함수가 즉시 실행되지 않게 하고, 클릭했을 때 실행이 되도록 해준다. 

배열 항목 수정하기

- User 컴포넌트에 계정명을 클릭했을때 색상이 초록으로 바뀌고, 다시 누르면 검정색으로 바뀌도록 구현한다.

 

1. App 컴포넌트의 users 배열 안의 객체 안에 active 라는 속성을 추가한다.

import React, { useRef, useState } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';

function App() {
  const [inputs, setInputs] = useState({
    username: '',
    email: ''
  });
  const { username, email } = inputs;
  const onChange = e => {
    const { name, value } = e.target;
    setInputs({
      ...inputs,
      [name]: value
    });
  };
  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);
  const onCreate = () => {
    const user = {
      id: nextId.current,
      username,
      email
    };
    setUsers(users.concat(user));

    setInputs({
      username: '',
      email: ''
    });
    nextId.current += 1;
  };

  const onRemove = id => {
    // user.id 가 파라미터로 일치하지 않는 원소만 추출해서 새로운 배열을 만듬
    // = user.id 가 id 인 것을 제거함
    setUsers(users.filter(user => user.id !== id));
  };

  return (
    <>
      <CreateUser
        username={username}
        email={email}
        onChange={onChange}
        onCreate={onCreate}
      />
      <UserList users={users} onRemove={onRemove} onToggle={onToggle} />
    </>
  );
}

export default App;

 

2. User 컴포넌트에서 방금 넣어준 active 값에 따라 폰트의 색상을 바꿔주도록 구현한다.

import React from 'react';

function User({ user, onRemove }) {
  return (
    <div>
      <b
        style={{
          cursor: 'pointer',
          color: user.active ? 'green' : 'black'
        }}
      >
        {user.username}
      </b>

      <span>({user.email})</span>
      <button onClick={() => onRemove(user.id)}>삭제</button>
    </div>
  );
}

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

export default UserList;

 

3. onToggle 이라는 함수를 구현한다.

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

import React, { useRef, useState } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';

function App() {
  const [inputs, setInputs] = useState({
    username: '',
    email: ''
  });
  const { username, email } = inputs;
  const onChange = e => {
    const { name, value } = e.target;
    setInputs({
      ...inputs,
      [name]: value
    });
  };
  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);
  const onCreate = () => {
    const user = {
      id: nextId.current,
      username,
      email
    };
    setUsers(users.concat(user));

    setInputs({
      username: '',
      email: ''
    });
    nextId.current += 1;
  };

  const onRemove = id => {
    // user.id 가 파라미터로 일치하지 않는 원소만 추출해서 새로운 배열을 만듬
    // = user.id 가 id 인 것을 제거함
    setUsers(users.filter(user => user.id !== id));
  };
  const onToggle = id => {
    setUsers(
      users.map(user =>
        user.id === id ? { ...user, active: !user.active } : user
      )
    );
  };
  return (
    <>
      <CreateUser
        username={username}
        email={email}
        onChange={onChange}
        onCreate={onCreate}
      />
      <UserList users={users} onRemove={onRemove} onToggle={onToggle} />
    </>
  );
}

export default App;

 

useEffect

: useEffect 함수는 리액트 컴포넌트가 렌더링 될 때마다 특정 작업을 실행할 수 있도록 하는 Hook 이다.

- useEffect는 component가 mount(처음 나타났을 때) 됐을 때, component가 unmount(사라질 때) 됐을 때, component가 update(특정 props가 바뀔 때) 됐을 때, 특정 작업을 처리할 수 있다.

<기본 형태>

useEffect( function, deps )

- function : 수행하고자 하는 작업
- deps : 배열 형태이며, 배열 안에는 검사하고자 하는 특정 값 or 빈 배열

 

1. Component가 mount 됐을 때 (처음 나타났을 때)


 - 컴포넌트가 화면에 가장 처음 렌더링 될 때 한 번만 실행하고 싶을 때는 deps 위치에 빈 배열을 넣는다.

  useEffect(() => {
    console.log('렌더링 될 때 마다 실행된다');
  });


- 만약 배열을 생략한다면 리렌더링 될 때 마다 실행된다.

 

2. Component가 update 될 때 (특정 props, state가 바뀔 때) 

 

- 특정값이 업데이트 될 때 실행하고 싶을 때는 deps 위치의 배열 안에 검사하고 싶은 값을 넣어준다.

(의존값이 들어있는 배열 deps 이라고도 한다. dependency를 의미.)

const mounted = useRef(false);

useEffect(() => {
  if(!mounted.current){
    mounted.current = true;
  } else {
  //ajax
  }
},[바뀌는 값]);

 

3. Component가 unmount 될 때(사라질 때) & update 되기 직전에

 

- cleanup 함수 반환 (return 뒤에 나오는 함수이며 useEffect에 대한 뒷정리 함수라고 한다.)

- 언마운트 될 때만 cleanup 함수를 실행하고 싶을 때
: 두 번째 파라미터로 빈 배열을 넣는다.

- 특정값이 업데이트 되기 직전에 cleanup 함수를 실행하고 싶을 때
: deps 배열 안에 검사하고 싶은 값을 넣어준다.

반응형