Event Handling
function Event() {
const handleClick = () => {
alert('클릭했습니다.');
}
const handleClick2 = (e, str) => {
console.log(e);
alert(str);
}
return <>
<button onClick={handleClick}>클릭</button>
<button onClick={(e) => handleClick2(e, '클릭2 클릭')}>클릭2</button>
</>
}
export default Event;
React에서 event속성을 줄 때는 camelCase 사용, JSX 사용해 이벤트 핸들러 전달
함수에 인자를 담아 보낼땐 화살표 함수 사용
클래스 컴포넌트에서의 이벤트
import {Component} from "react";
class EventClass extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log(this);
alert('클래스형 컴포넌트');
}
handleClick2 =() => {
console.log('화살표함수', this);
alert('클래스형 컴포넌트 2번');
}
handleClick3() {
alert('클래스형 컴포넌트 3번');
};
render() {
return <>
<button onClick={this.handleClick}>클릭class</button>
<button onClick={this.handleClick2}>클릭class2번</button>
<button onClick={this.handleClick3.bind(this)}>클릭class3번</button>
</>
}
}
export default EventClass;
클래스 컴포넌트에서는 this
사용하여 이벤트 함수 접근
클래스 내에서 이벤트 함수 정의
일반 함수로 정의했을 경우, 생성자에 bind
사용 필수
화살표 함수로 정의했을 경우, 따로 생성자에 정의할 필요 없음(자동 바인딩)
render 내부에서 바로 바인딩할 수 있으나, 좋은 방법은 아님!
state, setState
React에서 유동적인 데이터 다루기 위한 개체, 계속 변하는 특정 상태(컴포넌트가 가지고 있는 값)
state가 변경될 시 자동 재렌더링(변수는 변경되도 렌더링되지 않음)
setState
메서드를 통해 상태를 변경할 수 있음
클래스형 컴포넌트에서만 사용가능
this.state
가 아닌 setState
로만 값 변경
setState
는 비동기적 동작함으로 이전 상태 기반으로 함수형태의 setState 사용
import {Component} from "react";
class Counter extends Component {
state = {
number : 0,
}
constructor(props) {
super(props);
this.handleIncrement = this.handleIncrement.bind(this);
}
handleIncrement() {
this.setState((prevState) => ({ number : prevState.number + 1 }));
}
handleDecrement = () => {
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;
클래스 컴포넌트 내부에 state
란 이름, 객체형식으로 선언
버튼 클릭시, 바인딩된 이벤트 함수 호출
this.setState
사용하여 state값 변경
this.setState((prevState)=> ({ number : prevState.number + 1}));
state.number의 값을 prevState(이전 상태)값을 기준으로 +1
렌더링 후 태그에서 state값 접근할 때는 this.state
사용
React Hook
클래스 컴포넌트에서만 사용 가능했던 state
와 lifeCycle
을 함수형 컴포넌트에서도 사용하도록 돕는 기능
use
로 시작(권장사항)import {useState} from "react";
export default function CounterFunc() {
const [number, setNumber] = useState(0);
const handleIncrement = () => {
setNumber(()=> number + 1);
}
const handleDecrement =() => {
setNumber(number - 1);
}
return <div>
<h1>{number}</h1>
<button onClick={handleIncrement}>증가</button>
<button onClick={handleDecrement}>감소</button>
</div>
};
useState()
의 인자는 state의 초기값(값의 형태는 자유)
useState()
함수의 반환값은 배열을 반환, 첫번째 배열값은 현재 state, 두번째 배열값은 state를 바꿔주는 setter 함수
setNumber(()=> number + 1)
- setter 함수 사용해 state값 변경
클래스형 컴포넌트 LifeCycle
모든 React 컴포넌트에 존재하는 생명주기
Mount
- DOM이 생성되고 웹브라우저 상에 나타났을 때
Update
- props나 state가 바뀌었을 때
Unmount
- 컴포넌트가 화면에서 제거될 때
import {Component} from "react";
class MyComponent extends Component {
state = {
childNumber : 0,
}
//생성될 때
componentDidMount() {
console.log('Mount');
}
//업데이트 될 때
componentDidUpdate(prevProps, prevState, snapshot) {
console.log('Update');
console.log('prevProps ', prevProps);
console.log('prevState ', prevState);
console.log('snapshot ', snapshot);
}
//삭제될 때, 자식 컴포넌트의 state값은 초기화됨
componentWillUnmount() {
console.log('Unmount');
}
changeChildNumberState = () => {
this.setState({ childNumber : this.state.childNumber + 1 });
}
render() {
return <>
<div>My Component {this.props.number}</div>
<button onClick={this.changeChildNumberState}>PLUS Child</button>
</>
}
}
class LifeCycleClass extends Component {
state = {
number : 0,
visible : true,
};
changeNumberState = () => {
this.setState({ number : this.state.number + 1} );
}
changeVisibleState = () => {
this.setState({ visible : !this.state.visible });
}
render() {
return <>
<button onClick={this.changeNumberState}>PLUS</button>
<button onClick={this.changeVisibleState}>ON/OFF</button>
{this.state.visible && <MyComponent number={this.state.number}/>}
</>
}
}
export default LifeCycleClass;
useEffect
컴포넌트가 처음 마운트/리렌더링/변수의 값이 변경될 때 특정 작업들을 실행할 수 있도록 하는 Hook
import {useState, useEffect} from "react";
function MyComponent({number}) {
const [text, setText] = useState('');
useEffect(()=> {
console.log('항상 실행됩니다.');
})
useEffect(()=> {
console.log('생성될때 실행됩니다');
return ()=> {
console.log('제거될때 실행됩니다');
}
}, []);
useEffect(()=> {
console.log('state가 변경될 때 실행됩니다');
}, [text]);
return <>
<div>My Component {number}</div>
<input type="text" value={text} onClick={(e)=> setText(e.target.value)}/>
</>
}
export default function LifeCycleFunc() {
const [number ,setNumber] = useState(0);
const [visible ,setVisible] = useState(true);
const changeNumberState = () => {
setNumber(() => number + 1);
}
const changeVisibleState = () => {
setVisible(() => !visible);
}
return (
<>
<button onClick={changeNumberState}>PLUS</button>
<button onClick={changeVisibleState}>ON/OFF</button>
{visible && <MyComponent number={number}></MyComponent>}
</>
)
}
useEffect(()=> , )
- 항상 실행
useEffect(()=>, [])
- 최초 컴포넌트가 생성될 때 실행
useEffect(()=> return.. ,[])
- 제거될 때 실행
useEffect(()=>, [state])
- state 값이 변경될 때 실행
Ref, useRef
컴포넌트 내부에서 HTML 태그에 접근 가능하게 하는 기능
클래스형 컴포넌트에서만 사용이 가능
함수형 컴포넌트에서는 useRef()
로 사용 가능
import React from "react";
class RefSample extends React.Component {
myInput = React.createRef();
handleFocus = () => {
this.myInput.current.focus();
};
render() {
return (
<>
<p>(클래스형 컴포넌트) 버튼 클릭시 input에 focus 처리</p>
<input ref={this.myInput}/>
<button onClick={this.handleFocus}>Focus</button>
</>
)
}
}
export default RefSample;
React.createRef()
로 클래스 내에 필드에 선언 후 태그에 ref
this
를 붙여 값으로 넣어 사용
Reference를 사용할 때는 this.current
로 사용
import {useRef} from "react";
const UseRef2 = () => {
const idRef = useRef(1);
const plusIdRef =() => {
idRef.current += 1;
console.log(idRef.current);
}
return (
<>
<p>useRef 로컬변수 사용</p>
<h2>{idRef.current}</h2>
<button onClick={plusIdRef}>plus ref</button>
</>
)
}
export default UseRef2;
useRef()
로 함수 내 변수에 선언 후 ref
에 값으로 넣어 사용
ref.current
로 접근 가능
컴포넌트가 렌더링되어도 값이 그대로 유지되는 속성을 이용해 로컬변수로도 사용 가능
useMemo
함수형 컴포넌트 안에서, 렌더링 될 때 특정 값이 바뀌었을 때만 연산을 실행
렌더링될 때 마다 컴포넌트가 호출될 때 매번 내부 정의된 함수가 실행되는 경우를 막고, 결과값을 메모리에 저장 후 재사용
import React, {useMemo, useState} from "react";
export default function UseMemo() {
const [count, setCount] = useState(0);
const [inputValue, setInputValue] = useState('');
const calc = useMemo(()=> {
console.log('calc...');
for(let i=0 ; i<100000 ; i++) {
return count * 2;
}
}, [count]);
return (
<>
<input value={inputValue} onChange={(e)=> setInputValue(e.target.value)}/>
<button onClick={()=> setCount(count + 1)}>Increment Count</button>
<p>Count : {count}</p>
<p>Dobuled Count : {calc}</p>
</>
)
};
useMemo()
의 두번째 인자값인 의존 배열에서 지정한 state가 바뀌는 경우에만 콜백함수를 실행
useCallback
useMemo
와 비슷하지만, useCallback
은 컴포넌트 내 함수를 새로 만들지 않고 재사용하여 사용
import React, { useState, useCallback } from "react";
export default function UseCallback() {
const [text, setText] = useState('');
const onChangeText = (e) => {
setText(e.target.value);
}
const onChangeTextUseCallback = useCallback((e)=> {
setText(e.target.value);
}, []);
return (
<>
<h1>useCallback Test</h1>
<input onChange={onChangeText}/>
<div>
<span>작성한 값 : {text || '없음'}</span>
</div>
</>
)
}
반복해서 생성되는 이벤트 핸들러 함수를 useCallback
으로 감싸주면 함수를 메모이제이션해 컴포넌트가 리렌더링 되더라도 두번째 인자인 의존배열에 할당된 state가 바뀌지 않는 한 기존 함수를 계속 반환
useReducer
현재 state와 업데이트를 위해 필요한 정보를 담은 액션 dispatch를 전달받아 새로운 상태를 반환하는 함수, useState
의 기능을 대체할 수 있음
import { useReducer } from "react";
const initialState = { count : 0 };
function reducer(state, action) {
switch(action.type) {
case 'INCREMENT': return { count : state.count + 1 };
case 'DECREMENT': return { count : state.count - 1 };
default : throw new Error('invalid action type');
}
}
export default function UseReducer() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
<p>Count : {state.count}</p>
<button onClick={() => { dispatch({ type : 'INCREMENT' }); }}></button>
<button onClick={() => { dispatch({ type : 'DECREMENT' }); }}></button>
</>
)
}
useReducer()
의 첫번째 인자값은 액션에 따라 작동하는 함수, 두번째 인자는 초기 state값을 가짐
컴포넌트 내부에 [state, dispatch]
를 가지는 reducer를 선언 후 dispatch()
로 업데이트 액션 값을 지정
useReducer()
는 업데이트 함수를 컴포넌트 외부에서 가져와 사용할 수 있는 이점이 있음
객체, 배열과 같이 하위에 접근할 요소가 많은 경우 useReducer()
를 이용하는게 좋음
머시써용