8️⃣.1️⃣ useState
가장 기본적인 Hook
함수형 컴포넌트에서 state 사용시 사용한다.
예시 코드
import { useState } from 'react';
const Counter = () => {
const [value, setValue] = useState(0); // useState 함수의 파라미터에 상태의 기본값을 넣어줌
// 함수는 배열을 반환하는데 배열의 첫 번째 원소는 상태값, 두 번째 원소는 상태를 설정하는 함수
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 사용시 한번에 하나의 상태값만 관리하기에 그냥 여러개를 사용하면 된다.
8️⃣.2️⃣ useEffect
리액트 컴포넌트가 랜더링될 때마다 특정 작업을 수행하도록 설정 가능한 Hook이다.
클래스형 컴포넌트의 componentDidMount와 componentDidUpdate를 합친 형태로 봐도 무관하다.
useEffect(() => {
console.log(`effect`);
});
8️⃣.2️⃣.1️⃣ 마운트 때만 실행 : 함수의 두번째 파라미터에 빈 배열을 넣어주면 된다.
useEffect(() => {
console.log(`마운트될 때만 실행됩니다`);
}, [])
8️⃣.2️⃣.2️⃣ 업데이트 때만 실행 : useEffect의 두번째 파라미터에 검사하고픈 값을 넣어주면 된다.
useEffect(() => {
console.log(`${name}이 업데이트될 때만 실행`)
}, [name]); //useState로 관리되는 상태, props로 전달받은 값일 사용해도 됨
8️⃣.2️⃣.3️⃣ 뒷정리하기 : 컴포넌트가 언마운트 되기전이나 업데이트 직전에 작업을 수행 하려면 useEffect에 뒷정리 함수
를 반환해야한다. 랜더링 될때마다 뒷정리 함수가 계속 나타나고, 뒷정리 함수가 호출될 때는
업데이트 직전의 값을 보여준다.
useEffect(() => {
console.log(`effect`);
console.log(name);
return () => {
console.log(`cleanup`);
console.log(name);
};
}, [name]);
App컴포넌트 적용)
import { useState } from 'react';
import Info from '../Hooks/useEffect/Info';
const App = () => {
const [visible, setVisible] = useState(false);
return (
<div>
<button onClick={() => {
setVisible(!visible);
}}>
{visible ? `숨기기` : `보이기`}
</button>
<hr />
{visible && <Info/>}
</div>
)
}
export default App;
언마운트 될때만 뒷정리 함수를 호출하려면
useEffect의 두번째 파라미터에 빈 배열을 넣으면 된다.
8️⃣.3️⃣ useReducer
useState보다 더 다양한 컴포넌트 상황에 따라 상태를 업데이트 할 때 사용한다.
리듀서는 현재상태, 그리고 업데이트에 필요한 정보를 담은 액션(action)값을 전달 받아
새로운 상태를 반환하는 함수이다. (새로운 상태를 만들 때는 불변셩을 지켜야함)
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;
}
}
8️⃣.3️⃣.1️⃣ 카운터 구현하기
useReducer의 첫번째 파라미터에는 리듀서 함수를 넣고,
두번째 파라미터는 해당 리듀서의 기본값을 넣는다.
state와 dispatch함수를 받아오며 state는 현재 상태, dispatch는 액션을 발생시키는 함수이다.
dispatch(action) 형태로 사용하며, 함수 안의 파라미터로 액션값을 넣어주면 리듀서 함수가 호출되는 구조이다.
액션은 주로 다음과 같은 형태로 이루어 진다
{
type: `INCREMENT`
//다른 값이 필요하면 추가 가능
}
import { 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;
8️⃣.3️⃣.2️⃣ 인풋 상태 관리
useReducer에서의 액션은 그 어떤 값도 사용 가능하다.
import { useReducer } from 'react';
const Info = () => {
const [state, dispatch] = useReducer(reducer, {
name: '',
value: '',
});
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>
<div>
<b>이름 : </b>{name}
</div>
<div>
<b>닉네임 : </b>{nickname}
</div>
</div>
</div>
);
};
export default Info;
8️⃣.4️⃣ useMemo
useMemo를 사용하면 함수 컴포넌트 내부에서 발생하는 연산을 최적화할 수 있다.
랜더링 과정에서 특정 값이 바뀌었을 때만 실행하고 바뀌지 않으면 이전 연산 결과를 다시 사용하는 방식이다.
예시 코드)⬇
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, setNumbers] = useState(``);
const onChange = e => {
setNumbers(e.target.value);
};
const onInsert = e => {
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumbers(``);
};
const avg = useMemo(() => getAverage(list), [list]);
//useMemo는 생성 함수와 함수의 의존성 값의 배열을 전달한다.
//배열이 없는 경우 랜더링 마다 새 값을 계산한다.
//의존성이 변경되었을 때만 메모이제이션된 값만 다시 계산한다.
return (
<div>
<input value={number} onChange={onChange} />
<button onClick={onInsert}>등록</button>
<ul>
{list.map((value, index) => (
<li key={index}>{value}</li>
//각 자식 요소들은 고유한 키 값을 가져야 하므로 index값을 key로 주었다.
))}
</ul>
<div>
<b>평균값 : </b>{avg}
</div>
</div>
);
};
export default Average;
8️⃣.5️⃣ useCallback
useCallback은 useMemo와 비슷하며, 랜더링 성능 최적화시 사용한다.
만들어 놨던 함수를 재사용 가능하다.
컴포넌트 랜더링이 자주 발생하던가 랜더링 할 컴포넌트가 많아지면 이 부분을 최적화 하는 것이 좋다.
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, setNumbers] = useState(``);
const onChange = useCallback(e => {
setNumbers(e.target.value);
}, []); //컴포넌트가 처음 렌더링될 때만 함수 생성
const onInsert = useCallback( e => {
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumbers(``);
}, [number, list]);
const avg = useMemo(() => getAverage(list), [list]);
//useMemo는 생성 함수와 함수의 의존성 값의 배열을 전달한다.
//배열이 없는 경우 랜더링 마다 새 값을 계산한다.
//의존성이 변경되었을 때만 메모이제이션된 값만 다시 계산한다.
return (
<div>
<input value={number} onChange={onChange} />
<button onClick={onInsert}>등록</button>
<ul>
{list.map((value, index) => (
<li key={index}>{value}</li>
//각 자식 요소들은 고유한 키 값을 가져야 하므로 index값을 key로 주었다.
))}
</ul>
<div>
<b>평균값 : </b>{avg}
</div>
</div>
);
};
export default Average;
useCallback의 첫번째 파라미터는 생서하고픈 함수, 두번째 파라미터는 배열을 넣는다.
배열에 어떤 값이 바뀔때 함수를 생성하는지 명시해야한다. 빈 배열은 앤더링 마다 실행한다.
함수 내부 의존값은 배열(두번째 파라미터)에 넣어야 한다.
8️⃣.6️⃣ useRef
함수 컴포넌트에서 ref를 쉽게 사용할 수 있게 해준다.
useRef를 사용하여 ref설정시 useRef를 통해 만든 객체안의 current 값이 실제 element를 가르킨다.
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, setNumbers] = useState(``);
const onChange = useCallback(e => {
setNumbers(e.target.value);
}, []); //컴포넌트가 처음 렌더링될 때만 함수 생성
const onInsert = useCallback( e => {
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumbers(``);
}, [number, list]);
const avg = useMemo(() => getAverage(list), [list]);
//useMemo는 생성 함수와 함수의 의존성 값의 배열을 전달한다.
//배열이 없는 경우 랜더링 마다 새 값을 계산한다.
//의존성이 변경되었을 때만 메모이제이션된 값만 다시 계산한다.
return (
<div>
<input value={number} onChange={onChange} />
<button onClick={onInsert}>등록</button>
<ul>
{list.map((value, index) => (
<li key={index}>{value}</li>
//각 자식 요소들은 고유한 키 값을 가져야 하므로 index값을 key로 주었다.
))}
</ul>
<div>
<b>평균값 : </b>{avg}
</div>
</div>
);
};
export default Average;
8️⃣.6️⃣.1️⃣ 로컬 변수 사용
로컬변수 : 랜더링과 상관없이 바뀔수 있는 값
ref 안의 값이 바뀌어도 컴포넌트가 랜더링 안된다.
랜더링과 관련되지 않은 값을 관리할 때만 사용한다.
import { useRef } from 'react';
const RefSample = () => {
const id = useRef(1);
const setId = (n) => {
id.current = n;
}
const printId = () => {
console.log(id.current)
}
return (
<div>
RefSample
</div>
);
};
export default RefSample;
8️⃣.7️⃣ 커스텀 Hooks 만들기
여러 컴포넌트에서 비슷한 기능을 공유할 경우, Hooks를 만들어 로직 재사용이 가능하다.
import { useReducer } from 'react';
function reducer(state, action) {
return {
...state,
[action.name]: action.value,
};
}
export default function useInputs(initialForm) {
const [state, dispatch] = useReducer(reducer, initialForm);
const onChange = e => {
dispatch(e.target);
};
return [state, onChange];
}
적용한 코드⬇
import { useInputs } from './InfoWithCustom';
const Info = () => {
const [state, onChange] = useInputs({
name: '',
value: '',
});
const {name, nickname} = state;
return (
<div>
<div>
<input name="name" value={name} onChange={onChange} />
<input name="nickname" value={nickname} onChange={onChange} />
</div>
<div>
<div>
<b>이름 : </b>{name}
</div>
<div>
<b>닉네임 : </b>{nickname}
</div>
</div>
</div>
);
};
export default Info;
다른 개발자들이 만든 Hooks
https://nikgraf.github.io/react-hooks/
https://github.com/rehooks/awesome-react-hooks
'React' 카테고리의 다른 글
React) 10장 TodoList 프로젝트 (0) | 2022.04.17 |
---|---|
React) 9장 컴포넌트 스타일링 (0) | 2022.04.16 |
React) 6장 컴포넌트 반복 (0) | 2022.04.12 |
React) 5장 ref:DOM에 이름 달기 (0) | 2022.04.12 |
React) 4장 이벤트 핸들링 (0) | 2022.04.12 |