본문 바로가기

front-end 국비과정 학습일지

국비지원 48일차 벨로퍼트:react를 다루는 기술 (이벤트 핸들링, map함수를 이용한 반복문, filter함수를이용한 요소 삭제)

이벤트 핸들링

이벤트란?
웹을 사용하는 사용자와 요소(DOM)가 상호작용 하는것을 의미한다

react에서 이벤트 사용시 주의사항
1 이벤트 이름을 카멜 케이스로 작성해야한다 
즉 html에선 onclick이지만 react에서는 카멜 케이스로 작명하는것이 원칙이므로 onClick이된다

2 컴포넌트 에는 이벤트를 설정 할 수 없다 
즉 컴포넌트를 다를 컴포넌에서 불러와 사용할 때 태그처럼 사용되는데 컴포넌트 태그에는 이벤트를 적용 할 수 없다는 말이다

3 이벤트의 실행 내용은 함수 형태로 작성해야한다 
ex)

const Say = () => {
  const [test, setTest] = useState('test');

  const test2 = () => {
    if (test === 'test') {
      setTest('setTest');
    } else {
      setTest('test');
    }
  };
  return (
    <>
      <div>{test}</div>
      <button onClick={test2}>change</button>
      <Say />
    </>
  );
};


이벤트의 이름을 onClick이라고 작성한것은 react는 이벤트이름을 카멜 케이스에 규칙을 따르기때문이다
해당 코드에서 Say라는 태그에는 이벤트를 설정 할 수 없다는것이 2번의 내용이고
button태그에 test2라는 함수를 onClick 이벤트에 명시한것이 3번의 내용이다

이벤트를 실행할 내용을 요소에 직접 적용 할 수도 있지만 이벤트가 동작할 로직을 함수로 만들어놓고 해당 함수를 이벤트에 적용하면 
좀 더 가독성이 좋아진다
ex)

const EventPractice = () => {
  const [value, setValue] = useState('');

  const changeValue = (e) => {
    setValue(e.target.value);
  };

  return (
    <>
      <h1>이벤트 연습</h1>
      <input
        type="text"
        placeholder="아무거나 입력해 보세요"
        onChange={changeValue}
        value={value}
      />
      <h1>{value}</h1>
      <button
        onClick={() => {
          alert(value);
          setValue('');
        }}
      >
        클릭!
      </button>
    </>
  );
};


위 코드는 changeValue라는 이벤트 내용을 함수형태로 정의해 놓고 onChange이벤트에 적용한것과 , button태그에 직접 함수를 정의한 예시이다
가독성의 차이가 별로 없다고 느껴질 수 있지만 이벤트를 실행하는 로직이 길어지면 길어질 수록 태그에 직접 실행내용을 정의하는 것이 가독성이 떨어짐을 느낄 수 있다고 판단하였다 


사용자가 입력값을 특정 키를 눌렀을 때 제출하는 예시

enterKey라는 로직에 주목하여 react에서 key수식어를 어떻게 만들어 쓰는지가 포인트이다
ex)

const EventPractice = () => {
  const [value, setValue] = useState('');

  const changeValue = (e) => {
    setValue(e.target.value);
  };

  const submit = () => {
    alert(value);
    setValue('');
  };
  const enterKey = (e) => {
    if (e.key === 'Enter') {
      submit();
    }
  };

  return (
    <>
      <h1>이벤트 연습</h1>
      <input
        type="text"
        placeholder="아무거나 입력해 보세요"
        onChange={changeValue}
        onKeyDown={enterKey}
        value={value}
      />
      <h1>{value}</h1>
      <button onClick={submit}>클릭!</button>
    </>
  );
};


사용자가 input창에 비밀번호를 입력했을때 옭고 그름을 판단하는 코드 
ex) 

const ValidationalSample = () => {
  const [passWord, setPassWord] = useState('');
  const [clicked, setClicked] = useState(false);
  const [validated, setValidated] = useState(false);

  const inputPassWord = (e) => setPassWord(e.target.value);
  const handleButtonClick = (e) => {
    setClicked(true);
    setValidated(passWord === '0000');
  };
  const enter = (e) => {
    if (e.key === 'Enter') {
      handleButtonClick();
    }
  };
  return (
    <>
      <input
        type="password"
        value={passWord}
        onChange={inputPassWord}
        onKeyDown={enter}
        className={
          clicked ? (validated ? 'success' : 'failure') : ''
        }
      />
      <button onClick={handleButtonClick}>검증하기</button>
    </>
  );
};



ref 
ref는 reference의 줄임말이다 주로 DOM 즉 요소에 직접 접근할때 사용한다

react에서 DOM에 직접 접근해야하는 상황 즉 ref가 사용되는 상황은 3가지이다
1 input요소를 focus 할 때 
2 스크롤 박스를 조작 할 때
3Canvas 요소에 그림을 그릴 때 



요소나 컴포넌트를 반복시켜주는 map

JS에서 map은 객체나 배열의 요소를 하나하나 꺼내어 원하는 내용으로 변경 하여 새로운 객채나 배열을 만들어주는 기능을한다
ex)

  const arr = [1, 2, 3, 4, 5];
  console.log(arr);

  const test = arr.map((el) => {
    return el * el;
  });
  console.log(test);


react에서는 map을 이용해 요소 하나하나를 태그안에 삽입 하여 반환 할 수 있기 때문에 반복문으로 사용 할 수 있다
ex)map을 이용해 li태그안에 names라는 요소 하나하나를 삽입하여 출력한 예시
추가 버튼을 클릭하거나 input창에서 enter키를 누르면 요소가 추가되는 코드이다

const IterationSample = () => {
  const names = ['눈사람', '얼음', '눈', '바람'];
  const editedName = names.map((el) => <li>{el}</li>);

  return (
    <>
      <ul>{editedName}</ul>
    </>
  );
};



Map반복문에서 사용되는 Key 
Key는 고유함을 나타내는데 이러한 고유함은 리엑트에서 어떤 요소가 변동되었는지 가상돔(Virtual DOM)이 
변경사항을 더욱 빠르게 감지하기 때문에 사용한다 

ex)map과 state, key를 이용한 동적 요소 생성 

const IterationSample = () => {
  const [name, setName] = useState([
    { id: 1, text: '눈사람' },
    { id: 2, text: '얼음' },
    { id: 3, text: '눈' },
    { id: 4, text: '바람' },
  ]);

  const [inputText, setInputText] = useState('');
  const [nextId, setNextId] = useState(5);

  const changeInput = (e) => {
    setInputText(e.target.value);
  };

  const addNew = () => {
    const nextNames = name.concat({
      id: nextId,
      text: inputText,
    });
    setNextId(nextId + 1);
    setName(nextNames);
    setInputText('');
  };

  const enter = (e) => {
    if (e.key === 'Enter') {
      addNew();
    }
  };

  const nameList = name.map((el) => {
    return <li key={el.id}>{el.text}</li>;
  });

  return (
    <>
      <input
        value={inputText}
        onChange={changeInput}
        onKeyDown={enter}
      />
      <button onClick={addNew}>추가</button>
      <ul>{nameList}</ul>
    </>
  );
};


위 코드에서 요소가 추가될때 배열에 push를 사용하지 않고 concat을 사용한이유는
push는 기존 배열에 변경사항이 생기고 concat은 기존배열에 변경사항을 더해서 새로운 배열을 만들어 주기 때문이다
왜 그렇게 해야하는지 이유를 따지자면 react는 성능상 불변성을 유지 해야하기 때문이다 
구체적인 이유를 아직은 알지못하기 때문에 이렇게 정리하겠다 

filter함수는 배열이나 객체에 조건을 걸어 조건을 만족하는 요소만을 출력하여 새로운 객체나 배열을 만들어낸다
ex) 

const number = [1, 2, 3, 4, 5];
  const restNumber = number.filter((num) => {
    return num > 3;
  });
위 코드에서 nuber라는 배열이 있고 restNumber라는 배열에 filter함수를 사용하여 요소를 순차적으로 num에 담아 3보다 큰지 비교한다
결국 restNumber에 배열은 3보다큰 4와5만 존재하는 새로운 배열이 생성된다 
react에선 이러한 filter가 map으로 반복한 요소를 삭제하는 기능을 한다

ex)filter를 이용해 map으로 생성한 요소를 삭제하는 코드
 
const IterationSample = () => {
  const [name, setName] = useState([
    { id: 1, text: '눈사람' },
    { id: 2, text: '얼음' },
    { id: 3, text: '눈' },
    { id: 4, text: '바람' },
  ]);

  const [inputText, setInputText] = useState('');
  const [nextId, setNextId] = useState(5);

  const changeInput = (e) => {
    setInputText(e.target.value);
  };

  const addNew = () => {
    const nextNames = name.concat({
      id: nextId,
      text: inputText,
    });
    setNextId(nextId + 1);
    setName(nextNames);
    setInputText('');
  };

  const enter = (e) => {
    if (e.key === 'Enter') {
      addNew();
    }
  };

  const remove = (id) => {
    const nextNames = name.filter((el) => el.id !== id);
    setName(nextNames);
  };

  const nameList = name.map((el) => {
    return (
      <li key={el.id} onDoubleClick={() => remove(el.id)}>
        {el.text}
      </li>
    );
  });

  return (
    <>
      <input
        value={inputText}
        onChange={changeInput}
        onKeyDown={enter}
      />
      <button onClick={addNew}>추가</button>
      <ul>{nameList}</ul>
    </>
  );
};