[React Basic] 이벤트 핸들링

Joah·2022년 9월 23일
0

React Basic

목록 보기
21/25

게시글은 리액트 공부용이며 출처를 제시합니다.
출처: 소플의 처음 만난 React, 리액드를 다루는 기술, 모던 자바스크립트 deep dive

컴퓨터 프로그래밍에서 이벤트는 사건이다.
예를 들면 사용자가 버튼을 클릭하는 사건도 하나의 이벤트라고 볼 수 있다.
여기에서 클릭한 사건을 클릭 이벤트라고 부른다.


🛼 이벤트 처리하기

DOM의 이벤트

<button onclick="activate()">
	Active  
</button>

React의 이벤트

<button onClick={activate}>
	Active  
</button>
  • React에서는 카멜 케이스를 사용한다.

  • 이벤트 처리 함수를 문자열이 아닌 함수 그대로를 전달한다.

  • DOM 요소에만 이벤트를 설정할 수 있다.

    • div, button, input 등의 DOM요소에는 이벤트를 설정할 수 있지만 우리가 직접 만든 컴포넌트에는 이벤트를 자체적으로 설정할 수 없다.
      MyCompoenent에 onClick 값을 설정한다면 MyComponent를 클릭할 때 doSomething 함수를 실행하는 것이 아니라 그냥 이름이 onClick인 props를 Mycomponent에게 전달해 줄 뿐이다.
      <MyComponent onClick={doSomething}/>
      하지만 전달받은 props를 컴포넌트 내부의 DOM 이벤트로 설정할 수 있다.
      <div onClick={this.props.onClick}></div>

이벤트 핸들러

어떤 이벤트가 발생했을 때 해당 이벤트를 처리하는 함수가 있는데 이것을 이벤트 핸들러라고 한다. 또는 이벤트가 발생하는 것을 계속 듣고 있다는 의미로 이벤트 리스너라고 부르기도 한다.

function Toggle(props){
	const [isToggleOn, setIsToggleOn] = useState(true);
  	
  	//화살표 함수 사용
  	const handleClick = () => {
    	setIsToggle((isToggleOn) => !isToggleOn);
    }
    
    return (
    	<button onClick={handleClick}>
      		{isToggleOn? "켜짐":"꺼짐"}
		</button>
    );
}

🛼 Arguments 전달하기

Arguments는 주장, 논쟁, 말다툼이라는 뜻이 있다. 여기서는 주장이라는 뜻에 더 가깝다. 함수에 주장할 내용이라고 이해하면 된다.

함수에 전달할 데이터를 Arguments라고 하며 같은 의미로 파라미터라고도 한다. 한국말로는 매개변수라고 부른다.

이벤트 핸들러에게 매개변수를 전달해야 하는 경우는 많다.
예를 들어 특정 사용자 프로필을 클릭했을 때 해당 사용자의 아이디를 매개변수로 전달해서 정해진 작업을 처리해야 하는 경우가 있다.

function MyButton(props){
	const handleDelete = (id, event) => {
    	console.log(id, event.target);
    };
  return (
  	<button onClick={(event)=> handleDelete(1, event)}>삭제하기</button>
  )
}

🛼 예제를 통한 실습

🏝 onChange 이벤트 핸들링하기

📍 이벤트 객체와 onChange 이벤트 설정

<input
  type="text"
  name="message"
  placeholder="입력하세요"
  onChange={(e) => {
    console.log(e);
  }}
 />

콘솔에 기록되는 e 객체는 SyntheticEvent로 웹 브라우저의 네이티브 이벤트를 감싸는 객체이다.

Your event handlers will be passed instances of SyntheticEvent, a cross-browser wrapper around the browser’s native event. It has the same interface as the browser’s native event, including stopPropagation() and preventDefault(), except the events work identically across all browsers.

📍SyntheticEvent는 네이티브 이벤트와 달리 이벤트가 끝나고 나면 이벤트가 초기화되므로 정보를 참조할 수 없다.
따라서 onChange를 주고 "안녕하세요"에서 한글자 씩 작성할때 마다 콘솔에 이벤트 객체는 나타나지만 각각 이벤트들의 value 값을 보면 전부 "안녕하세요"라고 쓰여 있다. "ㅇ","ㅏ","ㄴ" 이 아니라

만약 비동기적으로 이벤트 객체를 참조할 일이 있다면 e.persist() 함수를 호출한다.

만약 인풋값을 하나하나 출력하고 싶다면 e.target.value로 확인하자
그럼 값이 바뀔 때마다 바뀌는 값을 콘솔에 기록하게 된다.


📍 state에 input값 담기

const EventPractice = () => {
  const [message, setMessage] = useState("");
  return (
    <div>
      <h1>이벤트 연습</h1>
      <input
        type="text"
        name="message"
        placeholder="입력하세요"
        value={message}
        onChange={(e) => {
          setMessage(e.target.value);
        }}
      />
      <h2>{message}</h2>
	//h2태그에 input에 작성한 값이 실시간으로 렌더링되면서 나타난다. state에 바뀌는 값을 담아서
    </div>
  );
};

📍 버튼을 누를 때 comment 값을 공백으로 설정

const EventPractice = () => {
  const [message, setMessage] = useState("");
  return (
    <div>
      <h1>이벤트 연습</h1>
      <input
        type="text"
        name="message"
        placeholder="입력하세요"
        value={message}
        onChange={(e) => {
          setMessage(e.target.value);
        }}
      />
      <button
        onClick={() => {
          //변수값을 문자열로 나타내야 알림창에 문자열 값이 출력된다.
          //그렇지 않으면 "Object object"가 출력된다.
          alert(`${message}`);
          setMessage("");
        }}
      >
        please click to reset
      </button>
    </div>
  );
};

🏝 임의 메서드 만들기

이벤트에 실행할 자바스크립트 코드를 전달하는 것이 아니라 함수 형태의 값을 전달한다. 위에서는 이벤트 처리를 할 때 렌더링 하는 동시에 함수를 만들어서 전달했다.
이 방법 대신 함수를 미리 준비하여 전달하는 방법도 있다.
성능상으로는 차이가 거의 없지만 가독성은 훨씬 높다.


📍 기본 방식

메서드 이름 정하는 쉬운 방법
규칙이 따로 있는 것은 아니지만 시작은 handle로 하는 것을 권장한다.

const EventPractice = () => {
  const [message, setMessage] = useState("");

  const handleChange = (e) => {
    setMessage(e.target.value);
  };

  const handleClick = () => {
    alert(`${message}`);
    setMessage("");
  };

  return (
    <div>
      <h1>이벤트 연습</h1>
      <input
        type="text"
        name="message"
        placeholder="입력하세요"
        value={message}
        onChange={handleChange}
      />
      <h2>{message}</h2>
      <button onClick={handleClick}>please click to reset</button>
    </div>
  );
};

🏝 input 여러 개 다루기

지금까지 input 값은 state에 넣는 방법을 알아봤다. 하지만 input이 여러 개일 때는 어떻게 작업을 할까?

const EventPractice = () => {
  const [message, setMessage] = useState("");
  const [userName, setUserName] = useState("");

  const handleMessageChange = (e) => {
    setMessage(e.target.value);
  };
  const handleNameChange = (e) => {
    setUserName(e.target.value);
  };

  const handleClick = () => {
    alert(`${userName} : ${message}`);
    setMessage("");
    setUserName("");
  };

  return (
    <div>
      <h1>이벤트 연습</h1>
      <input
        type="text"
        name="username"
        placeholder="사용자명"
        value={userName}
        onChange={handleNameChange}
      />
      <input
        type="text"
        name="message"
        placeholder="입력하세요"
        value={message}
        onChange={handleMessageChange}
      />
      <h2>{`${userName} : ${message}`}</h2>
      <button onClick={handleClick}>please click to reset</button>
    </div>
  );
};

export default EventPractice;


📍onKeyPress 이벤트 핸들링

키를 눌렀을 때 발생하는 KeyPress 이벤트를 처리해보자.
comment 인풋에서 enter를 눌렀을 때 handleClick 메서드를 호출하도록 해보자

const EventPractice = () => {
  const [message, setMessage] = useState("");
  const [userName, setUserName] = useState("");

  const handleMessageChange = (e) => {
    setMessage(e.target.value);
  };
  const handleNameChange = (e) => {
    setUserName(e.target.value);
  };

  const handleClick = () => {
    alert(`${userName} : ${message}`);
    setMessage("");
    setUserName("");
  };

  const handleKeyPress = (e) => {
    if (e.key === "Enter") {
      handleClick();
    }
  };

  return (
    <div>
      <h1>이벤트 연습</h1>
      <input
        type="text"
        name="username"
        placeholder="사용자명"
        value={userName}
        onChange={handleNameChange}
      />
      <input
        type="text"
        name="message"
        placeholder="입력하세요"
        value={message}
        onChange={handleMessageChange}
		//두번째 인풋창 작성하고 엔터를 누르면 handleClick 함수가 실행된다.
        onKeyPress={handleKeyPress}
      />
      <h2>{`${userName} : ${message}`}</h2>
      <button onClick={handleClick}>please click to reset</button>
    </div>
  );
};

export default EventPractice;

이렇게 input창이 두 개밖에 없다면 이런 코드는 나쁘지 않지만 만약 인풋의 갯수가 1억개가 넘는다면 e.target.name을 활용하여 useState를 문자열이 아닌 객체를 넣어보는 것이 효율적이다.

const EventPractice = () => {
  const [form, setForm] = useState({
    username: "",
    message: "",
  });

  const { username, message } = form;
  //구조분해할당

  const onChange = (e) => {
    const nextForm = { ...form, [e.target.name]: e.target.value };
    //form은 객체이기 때문에 데이터를 수정할때 얕은 복사로 불변성을 지킨다.
    //객체 안에서 key를 []로 감싸면 그 안에 넣은 레퍼런스가 가리키는 실제 값이 key값으로 사용된다.
    setForm(nextForm);
  };

  const handleClick = () => {
    alert(username + ":" + message);
    setForm({
      username: "",
      message: "",
    });
  };

  const handleKeyPress = (e) => {
    if (e.key === "Enter") {
      handleClick();
    }
  };

  return (
    <div>
      <h1>이벤트 연습</h1>
      <input
        type="text"
        name="username"
        placeholder="사용자명"
        value={username}
        onChange={onChange}
      />
      <input
        type="text"
        name="message"
        placeholder="입력하세요"
        value={message}
        onChange={onChange}
        onKeyPress={handleKeyPress}
      />
      <h2>{`${username} : ${message}`}</h2>
      <button onClick={handleClick}>please click to reset</button>
    </div>
  );
};

export default EventPractice;

여러 input 엘리먼트를 제어해야할 때, 각 엘리먼트에 name 어트리뷰트를 추가하고 event.target.name 값을 통해 핸들러가 어떤 작업을 할 지 선택할 수 있게 해줍니다.
주어진 input 태그의 name에 일치하는 state를 업데이트하기 위해 계산된 속성명을 사용한다.

profile
Front-end Developer

0개의 댓글