new TIL. 데이터 추가/제거 기능 구현

유자탱자🍋·2021년 4월 19일
1
post-thumbnail

input에 입력된 데이터를 추가하고, 더블 클릭한 데이터를 제거하는 기능을 구현하고자 한다.


1. state 설정

map 함수를 활용하여 리스트를 구현할 것이기 때문에 key 역할을 할 id도 객체에 담아준다.

  const [names, setNames] = useState([
    { id: 1, text: 'React' },
    { id: 2, text: 'JS' },
    { id: 3, text: 'SASS' },
    { id: 4, text: 'Styled Component' },
  ]);

미리 설정한 데이터 외 추가될 데이터가 있기 때문에 state 값을 업데이트 시켜줄 수 있어야 한다.

  const [nextId, setNextId] = useState(5);
  const [nextText, setNextText] = useState('');

2. map 함수 구현

기존 배열로 새로운 배열을 만드는 map 함수를 활용하여 list를 구현한다.
여기서 names는 처음에 설정한 state 값, name은 배열 내 각 요소를 의미한다.

      <ul>
        {names.map(name => (
          <li key={name.id}>
            {name.text}
          </li>
        ))}
      </ul>

3. 데이터 추가 기능 구현

데이터를 추가하기 위해 우선 input과 button을 만들어준다.
여기서 초기값인 value는 새롭게 입력될 nextText로 설정해준다.
❗️이 초기값이 없다면 나중에 button을 클릭한 후 입력된 값을 초기화하는 기능을 구현할 수 없다.

또한, 입력된 값으로 state 값을 업데이트 시켜주기 위해 onChange 이벤트도 추가해준다.
여기서 엔터를 쳤을 때도 list에 추가될 수 있게 구현하기 위해 onKeyPress 이벤트도 함께 넣어준다.

 <input
        type="text"
        name="newStack"
        value={nextText}
        onChange={onChangeInput}
        onKeyPress={onKeyPressInput}
      />
  const onChangeInput = e => {
    setNextText(e.target.value);
  };

  const onKeyPressInput = e => {
    if (e.key === 'Enter') {
      onClickInput();
    }
  };

🧐 e는 무엇일까?
콘솔 로그를 통해 SyntheticBaseEvent가 찍히는 것을 확인할 수 있다. 이벤트 핸들러는 모든 브라우저에서 이벤트를 동일하게 처리하기 위한 이벤트 래퍼 SyntheticEvent 객체를 전달받는다고 한다. 객체를 확인해보면 e.target.value는 input에 입력한 값이, e.key는 keyboard에서 누른 값이 찍히는 것을 알 수 있다.

사용자는 input에 추가하고 싶은 값을 입력하고, 엔터를 치거나 버튼을 클릭할 것이다. 그럼 onClick 이벤트를 통해 onClickInput 함수가 실행되도록 구현을 했다.

<button onClick={onClickInput}>레벨업</button>
  const onClickInput = () => {
    const nextNames = names.concat({
      id: nextId,
      text: nextText,
    });
    setNextId(nextId + 1);
    setNames(nextNames);
    setNextText('');
  };

concat 함수를 통해 names 배열에 새로운 id와 text를 추가해주고, setNextid를 통해 id를 업데이트 해준다. setNames를 통해 새로운 배열을 업데이트해주고, 마지막으로 input 창에 입력된 값을 초기화해주기 위해 setNextText('')를 사용해준다.

🧐 왜 concat 함수를 썼을까?
기존 배열에 새로운 요소를 추가하는 함수는 push와 concat이 있다. 둘의 차이는 push는 아예 기존 배열 자체를 변경해주고, concat은 기존 배열을 복사하여 새로운 배열에 요소를 추가한다.
리액트는 데이터를 변형시키지 않음으로써 성능 최적화라는 효과를 얻을 수 있다. 더 자세한 내용은 앞으로 차차 알아가기로 하고... 우선은 이러한 이유 때문에 concat 함수를 썼다는 사실만 기억하자!


4. 데이터 제거 기능 구현

더블 클릭한 리스트 요소를 사라지게 하고 싶기 때문에 이벤트의 위치는 list에 둔다.

      <ul>
        {names.map(name => (
          <li key={name.id} onDoubleClick={() => onRemove(name.id)}>
            {name.text}
          </li>
        ))}
      </ul>

실행되는 onRemove 함수에서 어떤 값을 제거할지 알아야 하기 때문에 props로 더블 클릭한 요소의 id값을 넘겨준다.

  const onRemove = id => {
    const nextNames = names.filter(name => name.id !== id);
    setNames(nextNames);
  };

그럼 그 id 값을 받아 filter 함수로 제거해주는데, filter 함수를 쓰는 이유도 아까 concat 함수를 쓰는 이유와 동일하다. id 값이 더블 클릭된 요소의 id 값과 같지 않는 것만 남겨준다. 그리고 다시 setNames!

🧐 filter 함수

const numbers = [1,2,3,4,5,6];
const withoutThree - numbers.filter(number => number !== 3); 
// [1,2,4,5,6]

종합해보면,

function IterationSample() {
  const [names, setNames] = useState([
    { id: 1, text: 'React' },
    { id: 2, text: 'JS' },
    { id: 3, text: 'SASS' },
    { id: 4, text: 'Styled Component' },
  ]);

  const [nextText, setNextText] = useState('');
  const [nextId, setNextId] = useState(5);

  const onChangeInput = e => {
    setNextText(e.target.value);
  };

  const onKeyPressInput = e => {
    if (e.key === 'Enter') {
      onClickInput();
    }
  };

  const onClickInput = () => {
    const nextNames = names.concat({
      id: nextId,
      text: nextText,
    });
    setNextId(nextId + 1);
    setNames(nextNames);
    setNextText('');
  };

  const onRemove = id => {
    const nextNames = names.filter(name => name.id !== id);
    setNames(nextNames);
  };

  return (
    <div className="iterationSample">
      <h3>Skills</h3>
      <ul>
        {names.map(name => (
          <li key={name.id} onDoubleClick={() => onRemove(name.id)}>
            {name.text}
          </li>
        ))}
      </ul>
      <input
        type="text"
        name="newStack"
        value={nextText}
        onChange={onChangeInput}
        onKeyPress={onKeyPressInput}
      />
      <button onClick={onClickInput}>레벨업</button>
    </div>
  );
}

참고) 리액트를 다루는 기술

0개의 댓글