React정리6(배열 렌더링 및 추가, 삭제, 수정)

min seung moon·2021년 7월 19일
0

React공부(feat.패캠)

목록 보기
7/8

배열 렌더링

앞으로 저희는 다양한 라이브러리에서 많은 값을 배열(컬렉션) 형식으로 받아올 일이 많아요!
그럴 때 좀 더 효율적으로 렌더링을 하기 위해서 map(), concat(), filter() 등
함수가 갖고 있는 메소드를 활용하는 경우가 많습니다!
이번에는 위에 메소드를 활용하여 배열에 추가, 삭제, 수정 기능 등을 가볍게 맛보도록 해볼까요!

const arr = [1, 2, 3, 4, 5, 6, 7];
const square = n => n*n; // 제곱수를 만드는 함수
const squared = arr.map(square); // [1, 4, 9, 16, 25, 36, 49] 제곱수가 squared에 반환

배열.map(함수);

위와 같이 map은 기존의 배열을 이용하여 새로운 배열을 반환합니다!
이제는 React에서 한번 활용 해 볼까요!

      import React from 'react';

      //실질적인 UI를 구성하는 컴포넌트
      function User({user}) {
          return(
              <div>
                  <b>{user.username}</b><span>{user.email}</span>
              </div>
          )
      };
      
      export default function UserList() {

          const users = [
              {
                  id : 1,
                  username : 'velopert',
                  email : 'public.velopert@gmail.com'
              },
              {
                  id : 2,
                  username : 'mms',
                  email : 'mms@gmail.com'
              },
              {
                  id : 3,
                  username : 'liz',
                  email : 'liz@gmail.com'
              },
          ];
      
          return (
              <div>
                  {/* 이렇게 사용할 경우 가변하는 길이에 맞추기가 힘들다 */}
                  {/* <User user={users[0]}/>
                  <User user={users[1]}/>
                  <User user={users[2]}/> */}
      
                  {/* key는 각 원소들의 고유값을 줌으로서 나중에 렌더링 최적화하는데 도움을 줌
                  key는 객체마다 다 다른 고유의 값이어야 함, 중복 되면 안됨 */}
                  {/* key로 사용할 값이 없을 때, map을 사용할 때 콜백함수의 두번째 파라메터인 index값을 사용
                  하지만 성능적으로 최적화되는데 도움이 되지는 않기 때문에 권장하지는 않음 */}
      
                  {
                      users.map(
                          // key값이 없을 때 map 메소드의 두번째 파라메터인 index를 사용
                          // (user,index) => (<User user={user} key={index} /> )
                          user => ( <User user={user} key={user.id} /> )
                      )
                  }
              </div>
          )
      }

코드 안에도 설명이 같이 있는데요!
한번 더 설명을 드리자면 user라는 객체를 가진 배열을 각 각 UI에 맞춰서 출력할거에요!
값이 고정적이고 추가가 될 일이 없거나 삭제가 될 일이 없다면

<User user={users[0]} />
<User user={users[1]} />
<User user={users[2]} />

이렇게 사용을 해도 되겠지만 일반적으로 값이 정해지는 경우는 많이 없죠!
Size를 정해준다 하더라도 추가가 될 수도 삭제가 될 수 도 있기 때문인데요!
그렇기 때문에 .map()이라는 메소드를 통해서 배열이 가진 값만큼 반복을 시켜줄 겁니다!

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

위와 같이 users안에 각 요소를 user이라는 변수에 넣어서 User 컴포넌트에 입력하죠!
key는 위에서도 간단히 소개를 했지만 key는 없으면 에러가 나고 로직이 조금 이상하게 작동합니다!
그래서 key 값을 설정해주는게 필수적인 사항이라고 보면 되구요!
key 값은 중복 되어서도 안되기 때문에 배열이 갖고 있는 고유의 값을 주는게 좋겠죠!
만약에 key 값으로 사용할게 없다면 .map() 메소드의 두번째 파라미터인 index 값을
키 값에 주어 사용해도 좋습니다!

아래에 key값이 없을 때와 있을 때를 비교해볼까요!

키 값이 없다면

      const arr = ['a', 'b', 'c', 'd'];
      arr.map(item => <div>{item}</div>);
      // 이 상황에서 중간에 'z'를 추가해주게 되면
      // arr = ['a', 'b', 'z', 'c', 'd'];
      <div>a</div>  ->  <div>a</div>
      <div>b</div>  ->  <div>b</div>
      <div>c</div>  ->  <div>z</div>
      <div>d</div>  ->  <div>c</div>
                    -+  <div>d</div>
      // <div>z</div>가 새로 생기는 것이 아닌 c 태그가 z로 바뀌로 d가 c로 바뀌고 d 태그가 새로 생김
      
      // 만약에 a를 삭제해주게 되면
      // arr = ['b', 'z', 'c', 'd'];
      <div>a</div>  ->  <div>b</div>
      <div>b</div>  ->  <div>z</div>
      <div>z</div>  ->  <div>c</div>
      <div>c</div>  ->  <div>d</div>
      <div>d</div>  --  
      // a 태그가 사라지는것이 아닌 값이 새로고침 되고 마지막 d 태그가 사라진다

이렇게 key 값이 없으면 새롭게 추가하거나 삭제한 값이 실제로 추가나 삭제가 아닌
값이 이동을 하고 다른 값이 추가되거나 삭제가 되죠!
이유는 각 배열의 원소가 정확히 무엇을 렌더링 하는지 모르고 index만 알고는
정확히 어떤 값을 렌더링 해야하는지 모르기 때문 입니다!
삭제가 되면 삭제가 아니라 바뀐다라고 생각을 해버리는 거죠!
그렇기에 key로 고유값을 설정하여 각 렌더링 한 결과에서 무엇을 가리키는지 명확하게 해주는게 좋아요!
그렇게 되면 새로운 값이 추가되거나 삭제되면 key 값을 통해 추가 또는 삭제가 됩니다

배열에 새 항목 추가

총 6 단계로 나누어 설명해 드리겠습니다!
마지막에는 최종 코드도 올릴 예정 입니다!

배열을 추가하기 위한 컴포넌트 생성

    export default function CreateUsers({ username, email, onChange, onCreate }) {
        return(
            <div>
                <input
                    name="username"
                    placeholder="계정명"
                    onChange={onChange}
                    value={username}
                />
                <input
                    name="email"
                    placeholder="이메일"
                    onChange={onChange}
                    value={email}
                />
                <button onClick={onCreate}>등록</button>
            </div>
        )
    }

CreateUsers라는 컴포넌트를 하나 만들어 줄거에요!
exprot default가 되어 있으니 js 파일 하나 만들어 주셔야 겠죠!
컴포넌트에는 총 4개의 props를 전달해 줄 예정입니다!
username, email은 값이 될거고 onChange, onCreate은 함수가 전달 될 거에요!
그렇게 해서 username을 받을 input태그와 email을 받을 input태그 총 2개와
배열에 등록하기 위한 onCreate 버튼 하나를 만들구요!
onChange는 값을 변경되는 것을 확인해야 되니 input태그에 넣어주시면 되겠죠!

1번 컴포넌트에서 입력받은 값을 저장할 state 생성

    const [inputs,setInputs] = useState({
        username : '',
        email : '',
      });

입력 받을 값을 저장할거기 때문에 inputs라는 변수명을 지어주었구요!
setInputs는 inputs의 값을 업데이트 해줄 함수 입니다!
useState를 보면 inputs에는 username과 email 프로퍼티가 있는 객체를 만들어 주었습니다!
많이 본 프로퍼티라 느낄 수있죠! 바로 1번에 input에 지정된 프로퍼티 입니다!

생성한 inputs State의 상태값을 구조화하여 사용

const {username, email} = inputs;

inputs에 할당 되어 있는 프로퍼티를 꺼내어 와서 사용할 예정이구요!
이렇게 하는 이유는 좀 더 효율적으로 사용하기 위함입니다!
객체이니 구조화를 하여도 {중괄호}로 묶어 주엇죠!

onChange 이벤트가 발생한 태그의 값을 받아와 inputs에 저장

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

첫 번째 함수인 onChange 함수 입니다!
e는 event 객체를 뜻하는 거구요!
이벤트 객체는 함수가 발생한 태그의 정보를 모두 갖고 있기 때문에 매우 유용합니다!

const {name, value } = e.target;

위에 코드는 이벤트가 발생한 객체를 찾은 다음에 구조화 할당을 해준 거에요!
궁금하신 분들은 consol.log(e); 또는 consol.log(e.target);을 입력해보세요!
그럼 input 태그에서 name과 value 값을 받아오겠죠!

setInputs({
	...inputs,
    [name] : value
    });

inputs에 값을 업데이트 해주어야 겠죠!
전 시간에도 말씀드렸듯이 값을 업데이트 할 때는 기존의 값을 넣어준 상태로 업데이트를 해야돼요!
그렇기에 ...inputs(스프레드 문법)을 활용하여 기존의 값을 넣어주고
[ name ]으로 입력받은 name에 따라 name이면 name, email이면 email에 value를 저장

상태가 변화할 때마다 리렌더링하여 화면에 보여줄 수 있게 useState로 묶어준다.

몇몇 분들이 새로고침과 리렌더링을 헷갈려하시는데 전혀 다른 동작을 합니다!
새로고침은 브라우저 자체를 새롭게 로딩을 하는 것이고
리렌더링은 브라우저에 보이는 React 부분만 렌더링을 다시 해주는 것입니다!
그렇기에 값을 useState에 추가를 해도 새로고침을 하면 삭제가 됩니다!

    const [users, setUsers] = useState([
    {
        id : 1,
        username : 'velopert',
        email : 'public.velopert@gmail.com'
    },
    {
        id : 2,
        username : 'mms',
        email : 'mms@gmail.com'
    },
    {
        id : 3,
        username : 'liz',
        email : 'liz@gmail.com'
    },
  ]);

users에 배열로 값 3개를 미리 초기화를 해두었습니다!
위에 onChange는 inputs의 값을 users에 저장하기 전에 임시적으로 저장해두는 메소드이며
이제 곧 만들 onCreate이 users에 입력할 메소드 입니다!

onCreate으로 배열에 값을 추가

  const onCreate = () => {
    const user = {
      id : nextId.current,
      username,
      email,
    };

    //기존배열, 새로운 배열
    // setUsers([...users, user]);

    //concat() 사용하기
    setUsers(users.concat(user));

    setInputs({
      username : '',
      email : '',
    })

    console.log(nextId.current);

    nextId.current+=1;
  }
profile
아직까지는 코린이!

0개의 댓글