▶ hook이란?
리액트 v16.8에 새로 도입된 기능으로 함수 컴포넌트에서도 상태 관리를 할 수 있는 useState, 렌더링 직후 작업을 설정하는 useEffect 등의 기능을 제공하여 React state와 생명주기기능을 연동할 수 있게 해주는 함수
- 종류: useState, useEffect,useReducer,useMemo,useCallback,useRef, 커스텀
1)useState: 함수형 컴포넌트에서 상태관리를 해주는 훅
<Counter.js>
import React,{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
● useState 정리
- import 구문을 통해 불러옴.
- useState 함수의 파라미터: 상태의 기본값 적음.
ex) 현재 예제의 기본값: 0으로 설정
- useState 호출 시 배열 반환: 첫번째 원소- 상태 값, 두번째 원소- 상태 설정 값
- 상태 값을 업데이트, 즉 변화시킴.
- 하나의 useState 함수 - 하나의 상태값만 관리
2)useEffect: 리액트 컴포넌트가 렌더링될 때마다 특정 작업을 수행하도록 설정할 수 있는 훅
<Info.js>
import {useState,useEffect} from 'react':
const Info=()=>{
const [name,setName]=useState("");
const [nickname,setNickname]=useState("");
useEffect(()=>{
console.log('렌더링이 완료되었습니다!');
console.log({name,nickname});
});
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}
</div>
<div>
<b> 닉네임:</b>{nickname}
</div>
</div>
</div>
);
};
export default Info;
● useEffect 정리
- import 구문으로 불러옴.
- 렌더링 되고 난 직후마다 실행, 두번째 파라미터 배열에 따라 실행조건 다름
1)업데이트될 때 실행시키지 않는 방법: 함수의 두번째 파라미터로 비어있는 배열을 넣어주기
ex) useEffect(()=>{
console.log('마운트 될 때만 실행됩니다!');
},[]);
2) 특정 값이 변경될 때만 호출하고 싶은 경우: 두번째 파라미터로 전달되는 배열 안에 검사하고 싶은 값을 넣어주기
ex) useEffect(()=>{
console.log('마운트 될 때만 실행됩니다!');
},[name]);
*배열 안: useState를 통해 관리하고 있는 상태 or props로 전달받은 값 모두 상관없음!
- 컴포넌트가 언마운트되기 전 or 업데이트 되기 직전 수행: cleanup 함수 반환하기
ex)
<Info.js>
useEffect(()=>{
console.log('effect');
console.log(name)
return ()=>{
console.log('cleanup');
console.log(name);
}
},[name]);
<App.js>
import React,{useState} from 'react';
import Info from './info';
const App = ()=>{
const [visible,setVisible]=useState(false);
return(
<div>
<button onClick={()=>setVisible(!visible);}}> {visible? '숨기기':'보이기'} </button>
<br/>
{visible&&<Info/>}
</div>
);
};
export default App;
//컴포넌트가 나타날때: 콘솔- effect, 사라질 때: 콘솔-cleanup
//렌더링될 때마다 뒷정리 함수가 계속 나타남, 뒷정리 함수가 호출될 때 업데이트되기 직전 값 보여줌
- 언마운트 될때만 뒷정리 함수 호출하고 싶다면: useEffecrt 함수의 두번째 파라미터에 비어있는 배열 넣기
3)useReducer: useState보다 다양한 컴포넌트 상황에 따라 다양한 상태를 다른 값으로 업데이트해주고 싶을 때 사용하는 훅
*리듀서: 현재 상태, 업데이트를 위해 필요한 정보를 담은 액션 값을 전달받아 새로운 상태를 반환하는 함수
<Counter.js>
import React,{useReducer} from 'react';
function reducer(state,action){
//action.type에 따라 다른 작업 수행
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
● useReducer 정리
- import 구문으로 불러옴.
- 첫번째 파라미터: 리듀서 함수, 두번째 파라미터: 해당 리듀서의 기본 값
- state: 현재 가리키고 있는 상태 dispatch: action을 발생시키는 함수
dispatch(action)과 같은 형태로, 함수 안에 파라미터로 액션 값을 넣어주면 리듀서 함수가 호출되는 구조
- 장점: 컴포넌트 업데이트 로직을 컴포넌트 바깥으로 빼낼 수 있음.
- 인풋 개수가 많아져도 코드를 깔끔하게 유지관리 가능
<Info.js>
<Info.js>
import React, {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}
</div>
<div>
<b> 닉네임:</b>{nickname}
</div>
</div>
</div>
);
};
export default Info;
- useReducer의 액션은 어떤 값도 사용이 가능
4)useMemo: 함수 컴포넌트 내부에서 발생하는 연산 최적화 가능
<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 [list,setList] = useState([]);
const [number,setNumber]= useState("");
const onChange = e =>{
setNumber(e.target.value);
}
const onInsert = e => {
const nextList = list.concat(parseInt(number));
setList(nextList)
setNumber("");
};
const avg= useMemo(()=>getAverage(list),[list]);
return(
<div>
<input value= {number} onChange={onChange}/>
<button onClick={onInsert}>등록</button>
<ul>
{list.map((value,index)=>(
<li.key={index}>{value}</li>
))}
</ul>
<div>
<b>평균값:</b>{avg}
</div>
</div>
);
};
export default Average;
● useMemo 정리
- import 통해 불러옴
- 렌더링하는 과정에서 특정 값이 바뀌었을 때만 연산을 실행, 원하는 값이 바뀌지 않았다면 이전에 연산했던 결과를 다시 사용
5)useCallback: 렌더링 성능을 최적화하는 상황에서 사용, 만들어 놨던 함수를 재사용 가능
<Average.js>
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 [list,setList] = useState([]);
const [number,setNumber]= useState("");
const onChange = useCallback(e =>{
setNumber(e.target.value);
},[]); //컴포넌트가 처음 렌더링 될때만 함수 생성
const onInsert = useCallback(() => {
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumber("");
},[number,list]); // number 혹은 list가 바뀌었을 때만 함수 생성
const avg= useMemo(()=>getAverage(list),[list]);
return(
<div>
<Input value={number} onChange={onChange}/>
<button onClick={onInsert}>등록</button>
<ul>
{list.map((value,index)=>(
<li.key={index}>{value}</li>
))}
</ul>
<div>
<b>평균값:</b>{avg}
</div>
</div>
);
};
export default Average;
● useCallback 정리
- import 통해 불러옴
- 첫 번째 파라미터: 생성하고 싶은 함수, 두번째 파라미터: 배열
*배열- 어떤 값이 바뀌없을 때 함수를 새로 생성해야 하는지 명시
- 비어 있는 배열을 넣게 되면 컴포넌트가 렌더링 될때 만들었던 함수를 계속해서 재사용
*배열 안에 number와 list를 넣게 되면 인풋 내용 변경 or 새로운 항목 추가 시 새로 만들어진 함수 사용
- 함수 내부에서 상태 값에 의존해야 할 때는 그 값을 반드시 두번 파라미터 안에 포함시키기
6)useRef: 함수 컴포넌트에서 ref를 쉽게 사용할 수 있도록 해 줌
● useRef 정리
-useRef를 사용하여 ref를 설정하면 useRef를 통해 만든 객체 안의 current 값이 실제 엘리먼트를 가리킴
-컴포넌트 로컬 변수를 사용해야 할 때도 useRef 활용 가능
*로컬변수: 렌더링 상관없이 바뀔 수 있는 값
'CS > 프로그래밍' 카테고리의 다른 글
CSS in JS (1) | 2024.01.13 |
---|---|
화살표 함수와 일반 함수 (0) | 2024.01.08 |
스코프, 스코프 체인 (1) | 2024.01.02 |
Context API (1) | 2024.01.01 |
JS, 이벤트 바인딩(Event Binding) (0) | 2023.12.26 |