useState
기본 sate 사용 예제
- App.js
import Counter from './Counter';
const App = () => {
return <Counter />;
};
export default App;
- Counter.js
import {useState} from 'react';
const Counter = () =>{
const [value, setValue] = useState(0);
return(
<div>
<p> 현재 카운터 값은 <b> {value}</b> 입니다. </p>
<button onClick={() => setValue(value + 1)}> +1 </button>
<button onClick={() => setValue(value - 1)}> -1 </button>
</div>
)
}
export default Counter;
여러개의 state 사용하기
-App.js
import Info from './Info';
const App = () => {
return <Info />;
};
export default App;
-Info.js
import {useState} from 'react';
const Info = () =>{
const [name, setName] = useState('');
const [nickname, setNickname] = useState('');
const onChangeName = e =>{
setName(e.target.value);
}
const onChangeNickname = e =>{
setNickname(e.target.value);
}
return(
<div>
<div>
<input value = {name} onChange={onChangeName}/>
<input value = {nickname} onChange={onChangeNickname}/>
</div>
<div>
<b>이름 : </b> {name}
<b>닉네임 : </b> {nickname}
</div>
</div>
)
}
export default Info;
input에 입력하는 값이 렌더링 되어 나온다.
useEffect
useEffect는 클래스형 컴포넌트의 componentDidMount와 componentDidUpdate 를 합친 형태로 볼 수 있다. 다음을 작성하고 확인해보자.
-Info.js
import {useEffect, useState} from 'react';
const Info = () =>{
const [name, setName] = useState('');
const [nickname, setNickname] = useState('');
useEffect(() => {
console.log('렌더링이 완료되었습니다.');
console.log({ name, nickname});
});
... // 위와 동일
}
export default Info;
업데이트 될 때는 useEffect의 함수가 실행되지 않도록하려면(처음 렌더링될 때만 실행됨) 함수의 파라미터로 빈 배열을 넣어주면된다.
useEffect(() => {
console.log('마운트 될 때만 실행됩니다.');
}, []);
만약 특정 값이 변경될 때만 호출하고 싶다면 다음과 같이 작성해보자.
useEffect(() => {
console.log(name);
}, [name]);
만약 컴포넌트가 언마운트되기 전이나 업데이트되기 직전에 어떠한 작업을 수행하고 싶다면 cleanup함수를 반환해주어야한다.
useEffect(() => {
console.log('effect');
console.log(name);
return () => {
console.log('cleanup');
console.log(name);
};
}, [name]);
- App.js
import Info from './Info';
import {useState} from 'react';
const App = () => {
const [visible, setVisible] = useState(false);
return (
<div>
<button onClick = {() => { setVisible(!visible)}}>
{visible ? '숨기기' : '보이기'}
</button>
{visible && <Info />}
</div>
)
};
export default App;
버튼을 클릭하면서 렌더링 과정을 볼 수 있다.
useReducer
ueReducer는 useState보다 더 다양한 컴포넌트 상황에 따라 다양한 상태를 다른 값으로 업데이트 하고 싶을 때 사용하는 hook이다. 현재 상태, 업데이트를 위해 필요한 정보를 담은 action 값을 전달받아 새로운 상태를 반환하는 함수이다.
리듀서 함수에서 새로운 상태를 만들 때는 반드시 불변성을 지켜주어야 한다.
- Counter.js
import {useReducer} from 'react';
function reducer(state, action){
switch(action.type){
case 'INCREMENT':
return {value: state.value +1};
case 'DECREMENT':
return {value: state.value -1};
default:
return state;
}
}
const Counter = () =>{
const [state, dispatch] = useReducer(reducer, {value:0});
return(
<div>
<p> 현재 카운터 값은 <b> {state.value}</b> 입니다. </p>
<button onClick={() => dispatch({type: 'INCREMENT'})}> +1 </button>
<button onClick={() => dispatch({type: 'DECREMENT'})}> -1 </button>
</div>
)
}
export default Counter;
- App.js
import Counter from './Counter';
const App = () => {
return <Counter />
};
export default App;
Info 예제에서 useState는 각각 관리하였는데, useReducer를 사용하면 input 태그에 name을 할당하고 e.target.name을 참조하여 작업을 처리할 수 있다. 훨씬 코드가 간결해지는 것을 볼 수 있다.
- Info.js
import {useReducer} from 'react';
function reducer(state, action){
return{
...state,
[action.name]:action.value
};
}
const Info = () =>{
const [state, dispatch] = useReducer(reducer, {name:'', nickname:''});
const {name, nickname} = state;
const onChange = e => {
dispatch(e.target);
}
return(
<div>
<div>
<input name="name" value = {name} onChange={onChange}/>
<input name="nickname" value = {nickname} onChange={onChange}/>
</div>
<div>
<b>이름 : </b> {name}
<b>닉네임 : </b> {nickname}
</div>
</div>
)
}
export default Info;
- App.js
import Info from './Info';
const App = () => {
return <Info />
};
export default App;
useMemo
useMemo는 함수 컴포넌트 내부에서 발생하는 연산을 최적화할 수 있다. 평균값을 계산하는 코드를 작성해보자.
useMemo는 li의 내용이 변경될 때만 호출된다.
- Average.js
import {useState, useMemo} from 'react';
const getAverage = numbers =>{
console.log('평균값 계산중');
if (numbers.length === 0) return 0;
const sum = numbers.reduce((a, b) => a + b);
return sum / numbers.length;
}
const Average = () => {
const [li, setList] = useState([]);
const [number, setNumber] = useState('');
const onChange = e =>{
setNumber(e.target.value);
}
const onInsert = () => {
const nextList = li.concat(parseInt(number));
setList(nextList);
setNumber('');
}
const avg = useMemo(() => getAverage(li), [li]);
return (
<div>
<div>
<input value = {number} onChange = {onChange}/>
<button onClick = {onInsert}>등록</button>
<ul>{li.map((value, index) => (
<li key={index}> {value} </li> ))}
</ul>
</div>
<div>
<b>평균값:</b>{avg}
</div>
</div>
);
};
export default Average;
- App.js
import Average from './Average';
const App = () => {
return <Average />
};
export default App;
useCallback
useCallback은 렌더링 성능을 최적화해야하는 상황에서 사용한다. 컴포넌트의 렌더링이 자주 발생하거나 렌더링해야 할 컴포넌트의 개수가 많아지면 이 부분을 최적화해주는 작업이 필요하다.
import {useState, useMemo, useCallback} from 'react';
const getAverage = numbers =>{
console.log('평균값 계산중');
if (numbers.length === 0) return 0;
const sum = numbers.reduce((a, b) => a + b);
return sum / numbers.length;
}
const Average = () => {
const [li, setList] = useState([]);
const [number, setNumber] = useState('');
const onChange = useCallback(e =>{
setNumber(e.target.value);
}, []);
const onInsert = useCallback(() => {
const nextList = li.concat(parseInt(number));
setList(nextList);
setNumber('');
}, [number, li])
const avg = useMemo(() => getAverage(li), [li]);
return (
<div>
<div>
<input value = {number} onChange = {onChange}/>
<button onClick = {onInsert}>등록</button>
<ul>{li.map((value, index) => (
<li key={index}> {value} </li> ))}
</ul>
</div>
<div>
<b>평균값:</b>{avg}
</div>
</div>
);
};
export default Average;
useRef
useRef를 사용하여 ref를 설정하면 useRef를 통해 만든 객체 안의 current 값이 실제 element를 가리킨다. 등록 후에 포인터가 input box를 가리킨다.
- Average.js
import {useState, useMemo, useCallback, useRef} from 'react';
const getAverage = numbers =>{
console.log('평균값 계산중');
if (numbers.length === 0) return 0;
const sum = numbers.reduce((a, b) => a + b);
return sum / numbers.length;
}
const Average = () => {
const [li, setList] = useState([]);
const [number, setNumber] = useState('');
const inputEl = useRef(null);
const onChange = useCallback(e =>{
setNumber(e.target.value);
}, []);
const onInsert = useCallback(() => {
const nextList = li.concat(parseInt(number));
setList(nextList);
setNumber('');
inputEl.current.focus();
}, [number, li])
const avg = useMemo(() => getAverage(li), [li]);
return (
<div>
<div>
<input value = {number} onChange = {onChange} ref={inputEl}/>
<button onClick = {onInsert}>등록</button>
<ul>{li.map((value, index) => (
<li key={index}> {value} </li> ))}
</ul>
</div>
<div>
<b>평균값:</b>{avg}
</div>
</div>
);
};
export default Average;
이외 customized hook을 만들어 서로 다른 component에서 사용할 수 있다. 또한 다른 개발자가 만든 hooks도 라이브러리에서 설치하여 사용할 수 있다고 한다.
'Programming > React.js' 카테고리의 다른 글
9. 컴포넌트 성능 최적화 (0) | 2022.08.24 |
---|---|
8. Component styling (0) | 2022.03.08 |
6. component의 lifecycle method (0) | 2022.03.06 |
5. 반복적으로 Component 사용하기 (0) | 2022.03.05 |
4. ref:DOM에 이름 달기 (0) | 2022.03.05 |