[포스코x코딩온] React-Event Handling, 합성 이벤트, state, setState, useState, Hook
React
Event Handling
https://ko.legacy.reactjs.org/docs/handling-events.html
이벤트 처리하기 – React
A JavaScript library for building user interfaces
ko.legacy.reactjs.org
React의 Event
- HTML Event
<button onClick="buttonEvent();">
Event Button
</button>
- React Event
<button onClick={buttonEvent}>
Event Button
</button>
//인라인 방식으로도 정의 가능
<button onClick={()=> alert("클릭되었습니다")}>
</button>
- 위 두 개의 차이점을 아시겠나요?
- React Event에는 ()가 없다.
- () 끝부분에서 클릭 없이 렌더링하는 동안 즉시 함수를 실행하기 때문에 사용하면 안 된다.
- React Event에는 ()가 없다.
- 인라인 방식으로도 정의할 수 있는데 이때, 화살표 함수를 꼭 사용해야 한다.
React의 Event 주의점
- React의 이벤트는 소문자 대신 카멜 케이스(camelCase)를 사용한다.
- JSX를 사용해 이벤트 핸들러를 전달한다.
- 기본DOM 요소에만 이벤트 설정이 가능하다.
- 직접 만든 컴포넌트에 이벤트 자체 설정 불가능
React합성 이벤트
- Synthetic Event
- 객체를 모든 브라우저에서 이벤트를 동일하게 처리하기 위한 Wrapper(래퍼) 객체
- Wrapper : 기본 기능을 감싸는 새로운 기능
- 다양한 이벤트가 더 있다.
- https://ko.legacy.reactjs.org/docs/events.html#clipboard-events
합성 이벤트(SyntheticEvent) – React
A JavaScript library for building user interfaces
ko.legacy.reactjs.org
함수에 인자 보내기
- 화살표 함수 이용하기
<button onClick={() => onClickEvent("인자1")}>클릭 이벤트</button>
<button onClick={(e) => onClickEvent2(e, "인자1")}>클릭 이벤트</button>
- e : "이벤트"를 의미하여 이 개체를 사용하여 이벤트에 대한 정보를 읽을 수 있다.
e 개체를 사용하여 전파 중지하기
- e.stopPopagation()
- 이벤트가 상위 구성 요소에 도달하는 것을 방지하려면 e.stopPopagation()을 호출하면 된다.
- 아래의 경우 버튼을 클릭했을 때 e.stopPopagation()을 호출하여 두 개의 버튼이 눌리는 것을 방지한다.
- 이벤트가 상위 구성 요소에 도달하는 것을 방지하려면 e.stopPopagation()을 호출하면 된다.
function Button({ onClick, children }) {
return (
<button onClick={e => {
e.stopPropagation();
onClick();
}}>
{children}
</button>
);
}
export default function Toolbar() {
return (
<div className="Toolbar" onClick={() => {
alert('You clicked on the toolbar!');
}}>
<Button onClick={() => alert('Playing!')}>
Play Movie
</Button>
<Button onClick={() => alert('Uploading!')}>
Upload Image
</Button>
</div>
);
}
- e.preventDefault()
- 몇 가지 이벤트에 대한 기본 브라우저 동작을 방지한다.
- 아래의 경우 <form> 내부의 버튼을 클릭 시 기본적으로 전체 페이지가 다시 로드되는 걸 방지해 준다.
- 몇 가지 이벤트에 대한 기본 브라우저 동작을 방지한다.
export default function Signup() {
return (
<form onSubmit={e => {
e.preventDefault();
alert('Submitting!');
}}>
<input />
<button>Send</button>
</form>
);
}
클래스 컴포넌트에서의 이벤트
- 클래스형 컴포넌트에서는 this를 사용해야 함수를 찾아갈 수 있다.
- state와 props와 동일
<button onClick={this.printConsole}>printConsole2</button>
<button onClick={this.handleButton}>handleButton</button>
함수에서 this 사용하기 (클래스 컴포넌트)
- bind 사용하기
- 화살표 함수 이용하기
import { Component } from "react";
class Counter extends Component {
//기본적으로 생성자 만들고 this.state를 사용해야 한다.
// constructor(props) {
// super(props);
// //this.state.number의 초기값 할당.
// this.state = {
// number: 0,
// };
// //바인딩
// this.handleIncrement = this.handleIncrement.bind(this);
// }
// handleIncrement() {
// // this.state.number++; 이렇게 작성하면 안된다.(직접적으로 변경하면 안된다.)
// this.setState({ number: this.state.number + 1 }); //setState를 사용해야 한다.
// }
//화살표 함수에서는 생성자와 this 없이 사용 할 수 있다.
state = {
number: 0,
};
handleDecrement = () => {
//setState는 호출 직후에 상태가 바로 업데이트 되지 않는다.
//비동기적으로 동작한다는 뜻
//React는 여러 setState 호출을 일괄 처리한다.
this.setState({ number: this.state.number - 1 }); //1번 setState
this.setState({ number: this.state.number - 1 }); //2번 setState
//2의 setState가 1의 setState의 결과를 기반으로 동작하지 않는다.
//===화살표 함수 형태로 사용. 밑에 있는 방법이 좀 더 올바를 방법이다. 위의 코드처럼 직접적으로
//===변경하게 되면 해킹 당했을 때 위험부담이 더 커진다.
this.setState((prevState) => ({ number: prevState.number - 1 })); //이전 상태를 기억한다.
this.setState((prevState) => ({ number: prevState.number - 1 })); //이전 상태를 기억한다.
};
render() {
return (
<div>
<h1>{this.state.number}</h1>
<button onClick={this.handleIncrement}>증가</button>
<button onClick={this.handleDecrement}>감소</button>
</div>
);
}
}
export default Counter;
공식문서에 나온 요약 내용
- You can handle events by passing a function as a prop to an element like "<button>".
- Event handlers must be passed, not called! "onClike={handleClick}", not "onClick={handleClick()}.
- You can define an event handler function separately or inline.
- Event handlers are defined inside a component, so they can access props.
- You can declare an event handler in a parent and pass it as a prop to a child.
- You can define your own event handler props with application-specific names.
- Events propagate upwards. Call "e.stopPropagation()" on the first argument to prevent that.
- Events may have unwanted default browser behavior. Call "e.preventDefault()" to prevent that.
- Explicitly calling an event handler prop from a child handler is a good alternative to propagation.
https://react.dev/learn/responding-to-events#adding-event-handlers
Responding to Events – React
The library for web and native user interfaces
react.dev
state와 setState
state
- React에서 앱의 유동적인 데이터를 다루기 위한 객체
- 계속해서 변하는 특정 상태
- 상태에 따라 다른 동작을 함
- 왜 사용하나?
- State가 변경될 시 자동으로 재랜더링 되기 때문
- 이 점이 변수와는 다른 점
- setState 메서드를 사용하여 상태를 변경할 수 있다.
Components often need to change what's on the screen as a result of an interatction. Typing into the form should update the input field, clicking "next" on an image carousel should change which image is displayed, clicking "buy" should put a product in the shopping cart. Components need to "remember" things: the current input value, the current image, the shopping cart. In React, this kind of component-specific memory is called state
https://react.dev/learn/state-a-components-memory
State: A Component's Memory – React
The library for web and native user interfaces
react.dev
state VS props
- props: 부모 컴포넌트에서 자식 컴포넌트에 데이터 전달 시 사용(읽기 모드)
- state: 특정 컴포넌트가 갖는 상태(값)
- 컴포넌트 내부에서 선언되고 내부에서 값을 변경함
주의할 점
- state는 원칙적으로 클래스형 컴포넌트에서만 사용가능
- 직접 this.state를 변경하지 말 것!
- 항상 setState를 사용
- setState는 비동기적으로 동작하므로, 이전 상태를 기반으로 다음 상태를 계산할 때 함수 형태의 setState를 사용
클래스형 컴포넌트
import { Component } from "react";
class EventClass extends Component {
//생성자
constructor(props) {
super(props); //부모 클래스인 component의 생성자 호출
this.handleClick = this.handleClick.bind(this);
}
//일반 함수
//binding 해줘야 한다.
// constructor(props) {
// super(props); //부모 클래스인 component의 생성자 호출
// this.handleClick = this.handleClick.bind(this);
// }
handleClick() {
console.log(this);
alert("클래스형 컴포넌트");
}
//화살표 함수
//binding을 안해도 된다.
handleClick2 = () => {
console.log("화살표 함수", this);
alert("클래스형 컴포넌트 2번");
};
render() {
return (
<>
<button onClick={this.handleClick}>클릭class</button>
<button onClick={this.handleClick2}>클릭class 2번</button>
</>
);
}
}
export default EventClass;
함수형 컴포넌트 useState
하기 전에 앞서 Hook을 먼저 알아보자
Hook
- 리액트(React) 훅은 2018년 10월에 React컨퍼런스에서 처음으로 소개
- 2019년에 React의 16.8버전에서 공식적으로 소개되고 사용
- React의 새로운 기능
- 클래스 컴포넌트에서만 가능했던 state(상태관리)와 lifecycle(라이프사이클)이 가능하도록 돕는 기능
Hook 사용 규칙
- 최상위 단계에서만 호출 가능
- 최상위 컴포넌트가 아니다.
- 반복문, 조건문, 중첩된 함수 내부에서 호출하면 안 되는 것
- Hook은 오로지 React 함수형 컴포넌트 안에서만 호출이 가능하다.
- 커스텀 훅 이름은 "use"로 시작(권장)
Hook 종류
- useState() : 상태 관리를 위한 가장 기본적인 훅
useState declares a state variable that you can update directly.
function ImageGallery(){
const[index, setIndex] = useState(0);
- useState 함수의 인자에는 상태의 초기값
- useState의 초기값은 숫자일 수도, 문자일 수도, 배열일 수도 있다. 즉, 값의 형태가 자유롭다
- useState 함수는 배열을 반환
- 첫 번째 원소: 현재 상태
- 두 번째 원소: 상태를 바꿔주는 setter 함수
- number라는 변수를 만들고 setNumber을 통해 number의 값을 설정해 줄 수 있다.
import { useState } from "react";
export default function CounterFunc() {
// const state = useState();
// //[undefined, f]가 나온다.
// //undefinded는 우리가 필요한 초기값을 넣으면 되고, f에는 함수를 넣으면 된다.
// console.log(state);
const [number, setNumber] = useState(0);
console.log(number);
function handleIncrement() {
setNumber(number + 1);
}
const handleDecrement = () => {
setNumber(number - 1);
};
return (
<div>
<h1>{number}</h1>
<button onClick={handleIncrement}>증가</button>
<button onClick={handleDecrement}>감소</button>
</div>
);
}
- useEffect(): 컴포넌트가 렌더링 될 때마다 특정 작업을 수행하도록 설정할 수 있는 훅
'useEffect' connects a component to an external system
function ChatRoom({ roomId }) {
useEffect(() => {
const connection = createConnection(roomId);
connection.connect();
return () => connection.disconnect();
}, [roomId]);
- useContext(): 리액트에서 전역적으로 접근 가능한 데이터나 함수를 관리하고, 필요한 컴포넌트에서 그 값을 바로 가져와 사용할 수 있게 도와주는 훅
'useContext' reads and subscribes to a context
function Button() {
const theme = useContext(ThemeContext);
// ...
- useReducer(): 복잡한 컴포넌트 상태 로직을 리듀스 함수를 통해 관리할 수 있는 훅
'useReducer' declares a state variable with the update logic inside a reducer function
- useMemo(): 메모이제이션을 통해 함수의 리턴 값을 재사용할 수 있게 해주는 훅
'useMemo' lets you cache result of an expensive calculation
function TodoList({ todos, tab, theme }) {
const visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]);
// ...
}
- useCallback(): 함수를 메모이제이션하여 불필요한 렌더링을 줄이게 해주는 훅
'useCallback' lets you cache a function definition before passing it down to an optimized component
- useRef(): 참조(reference)를 생성하고 관리할 수 있는 훅(DOM 접근, 변수 보존 등)
'useRef' declares a ref. You can hold any value in it, but most often it's used to hold a DOM node.
function Form() {
const inputRef = useRef(null);
// ...
- 더 다양한 Hook들이 있다.
Built-in React Hooks – React
The library for web and native user interfaces
react.dev
공식문서에 나온 요약 내용
- Use a state variable when a component needs to "remeber" some information between renders.
- State variables are declared by calling the "useState" Hook.
- Hooks are special functions that start with "use". They let you "hook into" React feature like state.
- Hooks might remind you of imports: they need to be called unconditionally. Calling Hooks, includeing "useState", is only valid at the top level of a component or another Hook.
- The "useState" Hook returns a pair of values: the current state and the function to update it.
- You can have more than one state variable. Internally, React matches them up by their order.
- State is private to the component. If you render it in two places, each copy gets its own state.
https://github.com/DongHo-Kang/KDT-8-web/tree/94422cc6387a49d57ea61f51f659bfc2b8acab1e/react_basic
React-Event Handling, 합성 이벤트, state, setState, useState, Hook