Hook은 React 버전 16.8부터 React 요소로 새로 추가되었습니다.
기존에 사용하던 Class를 이용한 코드를 작성할 필요 없이,
state와, 여러 React 기능을 사용할 수 있도록 만든 라이브러리
함수형 컴포넌트에서도 가변적인 상태를 지니고 있을 수 있게 해줍니다. 만약에 함수형 컴포넌트에서 상태를 관리
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>
</div>
);
};
import react, { useEffect } from "react";
useEffect(()=>{
}, [, deparray]);
React component가 렌더링 될 때마다, 종속성 배열의 value값이 바뀔 때마다 특정 작업(Sied effect)을 실행할 수 있도록 하는 리액트 Hook입니다.
uesEffect는 첫 번째 인자로 콜백 함수를 받고 두 번째 인자로 배열을 받는데 이 배열을 '종속성 배열' 이라고 합니다.
(※만약 종속성 배열이 비어있다면, useEffect는 최초로 렌더링될때만 실행됩니다.)
useEffect 는 기본적으로 렌더링 되고난 직후마다 실행되며, 두번째 파라미터 배열에 무엇을 넣느냐에 따라 실행되는 조건이 달라집니다.
만약 컴포넌트가 언마운트되기 전이나, 업데이트 되기 직전에 어떠한 작업을 수행하고 싶다면 useEffect 에서 뒷정리(cleanup) 함수를 반환해주어야 합니다.
이는 자주 리렌더링 될 경우 메모리 누수가 발생할 수 있다.
useEffect(() => {
return () => {
// cleanup
}
}, deparray);
단계마다 일일이 props를 넘겨주지 않고도 컴포넌트 트리 전체에 데이터를 제공
일반적인 React 어플리케이션에서 데이터는 props를 통해서 부모에서 자식에게 전달 되지만, 어플리케이션 안의 여러 컴포넌트들에게 props를 전달해줘야 하는 경우 context를 이용하면 명시적으로 props를 넘겨주지 않아도 값을 공유할 수 있게 해주는 것이다.
한마디로 데이터가 필요할 때마다 props를 통해 전달할 필요가 없이 context 를 이용해 공유한다!
//App.js
import React, { createContext } from "react";
import Children from "./Children";
// AppContext 객체를 생성한다.
export const AppContext = createContext();
const App = () => {
const user = {
name: "김채원",
job: "가수"
};
return (
<>
<AppContext.Provider value={user}>
<div>
<Children />
</div>
</AppContext.Provider>
</>
);
};
export default App;
//Children.js
import React from "react";
import { AppContext } from "./App";
const Children = () => {
return (
<AppContext.Consumer>
{(user) => (
<>
<h3>AppContext에 존재하는 값의 name은 {user.name}입니다.</h3>
<h3>AppContext에 존재하는 값의 job은 {user.job}입니다.</h3>
</>
)}
</AppContext.Consumer>
);
};
export default Children;
//Children.js(useContext를 적용하면)
import React, { useContext } from "react";
import { AppContext } from "./App";
const Children = () => {
// useContext를 이용해서 따로 불러온다.
const user = useContext(AppContext);
return (
<>
<h3>AppContext에 존재하는 값의 name은 {user.name}입니다.</h3>
<h3>AppContext에 존재하는 값의 job은 {user.job}입니다.</h3>
</>
);
};
export default Children;
추후 공부
함수형 컴포넌트 내부에서 발생하는 연산을 최적화
렌더링 하는 과정에서 특정 값이 바뀌었을 때만 연산을 실행하고 만약에 원하는 값이 바뀐 것이 아니라면 이전에 연산했던 결과를 다시 사용하는 방식입니다.
import React, { 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;
이벤트 핸들러 함수를 필요할 때만 생성
첫번째 파라미터에는 우리가 생성해주고 싶은 함수를 넣어주고, 두번째 파라미터에는 배열을 넣어주면 되는데 이 배열에는 어떤 값이 바뀌었을 때 함수를 새로 생성해주어야 하는지 명시해주어야 합니다.
import React, { 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(
e => {
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;
숫자, 문자열, 객체 처럼 일반 값을 재사용하기 위해서는 useMemo
그리고 함수를 재사용 하기 위해서는 useCallback
Average 컴포넌트에서 등록 버튼을 눌렀을 때 포커스가 인풋 쪽으로 넘어가도록
useRef 를 사용하여 ref 를 설정하면, useRef 를 통해 만든 객체 안의 current 값이 실제 엘리먼트를 가르키게 됩니다
import React, { useState, useMemo, 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 [list, setList] = useState([]);
const [number, setNumber] = useState('');
const inputEl = useRef(null);
const onChange = useCallback(e => {
setNumber(e.target.value);
}, []); // 컴포넌트가 처음 렌더링 될 때만 함수 생성
const onInsert = useCallback(
e => {
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumber('');
inputEl.current.focus();
},
[number, list]
); // number 혹은 list 가 바뀌었을 때만 함수 생성
const avg = useMemo(() => getAverage(list), [list]);
return (
<div>
<input value={number} onChange={onChange} ref={inputEl} />
<button onClick={onInsert}>등록</button>
<ul>
{list.map((value, index) => (
<li key={index}>{value}</li>
))}
</ul>
<div>
<b>평균 값:</b> {avg}
</div>
</div>
);
};
export default Average;
로컬 변수로 사용하여 렌더링은 되지않고 화면만 보이게 할 수 있다.
그 외 다양한 hooks을 만들어 사용할 수 있다.
참조
https://velog.io/@velopert/react-hooks#5-usememo
https://velog.io/@jminkyoung/TIL-6-React-Hooks-useContext-%EB%9E%80