🐕 커스텀훅
우리가 함수를 만드는 것처럼 훅을 커스텀해서 만들 수 있다.
함수 안에 이름을 지어주고 원하는 로직을 만들어주면 끝이다.
다만 커스텀 훅을 만들 때 주의할 점이 있는데
함수의 이름 시작을 use로 만들어줘야한다는 것이다.
네이밍이 어긋나게 되면 오류가 발생했을 때 리액트에서 적절한 경고메시지를 받을 수 없고
또 함수를 쓰는 당사자인 개발자가 코드를 읽기 어려워질 수 있기 때문이다.
👻간단하게 커스텀 훅을 작성하자
useInput.js
import React, { useState } from 'react';
export function useInput(initialValue) {
const [inputValue, setInputValue] = useState(initialValue);
const handleChange = (e) => {
setInputValue(e.target.value);
};
return [inputValue, handleChange];
}
export 문법을 통해 내보내줬다.
보통 export default 로 많이 내보냈던 기억이 있는데
외않돼..?하면서 좀 더 찾아봤는데
-- 그냥 코드 참고용
import { useState, useCallback } from 'react';
function useInputs(initialForm) {
const [form, setForm] = useState(initialForm);
// change
const onChange = useCallback(e => {
const { name, value } = e.target;
setForm(form => ({ ...form, [name]: value }));
}, []);
const reset = useCallback(() => setForm(initialForm), [initialForm]);
return [form, onChange, reset];
}
export default useInputs;
이렇게 작성하면 또 되네요?
아무튼 로직을 다른 파일로 빼준 다음 그걸 우리가 useState쓰듯이 불러와서 사용하면..?
App.js
import React, { useState } from 'react';
import { Fragment } from 'react';
import { useInput } from './useInput';
const App = () => {
const [inputValue, handleChange] = useInput('류지수그냥미쳤다');
const [inputValue2, handleChange2] = useInput('이은희그냥미쳤다');
const handleSubmit = () => {
alert(inputValue);
// setInputValue('');
};
return (
<>
<h1>유즈인풋</h1>
<input value={inputValue} onChange={handleChange} />
<input value={inputValue2} onChange={handleChange} />
<button onClick={handleSubmit}>확인</button>
</>
);
};
export default App;
어라..? 맛있다...?
그냥 불러와서 한줄만 써버리면 이 로직이 다 끝난다..?
useInput.js
import { useState } from 'react';
export function useInput(initialValue, submitAction) {
const [inputValue, setInputValue] = useState(initialValue);
const handleChange = (e) => {
setInputValue(e.target.value);
};
const handleSubmit = () => {
setInputValue('');
submitAction(inputValue);
};
return [inputValue, handleChange, handleSubmit];
}
이제 버튼 로직까지 한번에 처리해주고 싶으니까
받는 매개인자를 한개 더 만들어주고
리턴 해주는 배열에 handleSubmit 함수를 추가해줬습니다.
handleSubmit 함수는 인자로 받은 콜백함수를 실행시켜주는 일을 하고
setState를 호출해 상태를 빈 문자열로 바꿔주는 일을 하는 함수로 만들어줬어요
그런 다음 리턴값에 handleSubmit까지 추가시켜서 내보내주면?
App.js
const App = () => {
const [inputValue, handleChange, handleSubmit] = useInput(
'류지수그냥미쳤다',
displayMessage,
);
const [inputValue2, handleChange2, handleSubmit2] = useInput(
'이은희그냥미쳤다',
displayMessage,
);
당연히 내보낸 배열의 길이가 1 늘었으니 구조분해할당도 한개 더 늘려서 받아줍니다.
꼭 그렇게 해야한다고 누가 칼들고 협박한 건 아니지만
저렇게 안받아주면 세번째 배열에 담긴 뭔가는 사용할 수 없어지니까요..
세번째에 있는 handleSubmit 변수는 우리가 새로 만들어 내보내준 함수가 담기게 됩니다.
그리고 hanldeSubmit 에 담긴 함수가 호출하는건 우리가 추가로 넣어준 함수인거죠!
함수를 바로 만들어서 넣어줘도 괜찮지만 따로 만들어주겠습니다.
displayMessage라는 함수를 만들어줄게요
function displayMessage(message) {
alert(message);
}
displayMessage 함수는 아주아주 간단한 일을 하는 함수입니다.
alert(message)를 하고 종료되는 간단한 함수에요
우리는 useInput.js 단에서 callback 함수에
inputValue라는 스테이트의 값을 넣어줄거니까 그 값을 활용하기 위해서
매개변수를 받는 코드를 작성해줬어요!
이제 잘 되는지 확인해볼까요?
아주 잘 실행되네요
너무 멋지다..
🥶 좀 더 심화해서 useFetch도 만들어보자
app.js
import React, { useEffect, useState } from 'react';
import { Fragment } from 'react';
const App = () => {
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then((res) => res.json())
.then((res) => console.log(res));
}, []);
return (
<>
<h1></h1>
</>
);
};
export default App;
fetch는 자바스크립트에서 기본으로 제공되는 API 중 하나입니다.
useEffect를 통해 화면이 렌더된 최초 상황에만 fetch를 실행시켜주겠습니다.
의존성배열을 빈배열로 주면 최초 한번만 실행이 되겠죵
fetch 함수는 기본적으로 프로미스를 반환하기 때문에
프로미스 후속처리메서드 then 역시도 사용 할 수 있습니다.
then을 통해 프로미스의 resolve 값을 받아오고
.json() 메서드를 통해 데이터를 json 형태로 바꿔줍니다.
그 다음 한번 더 then을 체이닝해서 console.log메서드로 res에 어떤 값이 담겨있는지 확인을 해볼거에요
jsonplaceholder 사이트는 더미데이터를 제공해주는 재밌는 사이트입니다.
더미 데이터를 받아오는 작업을 하겠습니다.
https://jsonplaceholder.typicode.com/users
요 사이트에 들어가보시면 아주 재밌어용 복사해서 써보세요
우리의 유저데이터가 잘 담겨서 온것을 확인할 수 있군요
app.js
import React, { useEffect, useState } from 'react';
import { Fragment } from 'react';
const baseUrl = 'https://jsonplaceholder.typicode.com';
const App = () => {
const [data, setData] = useState(null);
const fetchUrl = (type) => {
fetch(baseUrl + '/' + type)
.then((res) => res.json())
.then((res) => setData(res));
};
useEffect(() => {
fetchUrl('users');
}, []);
return (
<>
<h1>페치함수</h1>
<pre>{JSON.stringify(data, null, 2)}</pre>
</>
);
};
export default App;
아까랑 동일한 동작을 하는 코드지만
구조를 조금 바꿔주었습니다.
함수를 따로 만들어서 밖으로 빼줬고
json 형태로 바꿔준 resolve 값을 setData에 전달해서
data의 상태를 변경시켜줬습니다.
pre태그의 안에 JSON의 정적메서드 .stringfy를 사용하여 값을 나열해주는 코드에요
잘못된 점이 없다면 화면에 잘 출력될 것입니다.
JSON.stringfy의 2,3번째 인자는 선택적으로 넣어줄 수 있는데
차이는 저걸 뺴고 안뺴고로 느껴보실 수 있으니 직접 해보세요
<>
<h1>페치함수</h1>
<button onClick={() => fetchUrl('users')}>Users</button>
<button onClick={() => fetchUrl('posts')}>Posts</button>
<button onClick={() => fetchUrl('todos')}>Todos</button>
<pre>{JSON.stringify(data, null, 2)}</pre>
</>
위 코드는 동일한 상태로
return 값 부분만 위와 같이 수정해줬습니다.
button을 세개 만들고 각각 onClick 이벤트가 발생할 때 마다
fetchUrl을 호출하는데 안에 넣는 인자를 각각 다르게 설정해주는거죠!
버튼을 누를때마다 새로운 데이터가 렌더링 됩니다.
이제 진짜 커스텀훅으로 만들어서 로직을 밖으로 빼줄게요
🌞useFetch를 만들자
useFetch.js
import { useState, useEffect } from 'react';
export function useFetch(baseUrl, initialType) {
const [data, setData] = useState(null);
const fetchUrl = (type) => {
fetch(baseUrl + '/' + type)
.then((res) => res.json())
.then((res) => setData(res));
};
useEffect(() => {
fetchUrl(initialType);
}, []);
return {
data,
fetchUrl,
};
}
커스텀 훅을 만들거니까 새로운 파일을 만들어줍니다.
아까 썼던 로직을 그대로 가져와주고
인자로 받는 건 baseUrl과 initialType 총 두가지에용
baseUrl에는 우리가 아까썼던 json~~~~ 이 들어갈거고
initialType에는 눌렀을때 각각 다른 페이지를 표시해주는 로직이 들어가겠죵?
그리고 객체 디스트럭처링 할당을 통해 값들을 밖으로 내보내줍니다.
객체 디스트럭처링 문법이 익숙하지 않으시면 유감
App.js
import React, { useEffect, useState } from 'react';
import { Fragment } from 'react';
import { useFetch } from './useFetch';
const baseUrl = 'https://jsonplaceholder.typicode.com';
const App = () => {
const { data: userData } = useFetch(baseUrl, 'users');
const { data: postData } = useFetch(baseUrl, 'posts');
return (
<>
<h1>유저</h1>
{userData && <pre>{JSON.stringify(userData[0], null, 2)}</pre>}
<h1>포스트</h1>
{postData && <pre>{JSON.stringify(postData[0], null, 2)}</pre>}
</>
);
};
export default App;
App.js로 돌아옵니다
객체디스트럭처링 할당에 익숙하지 않으신 저같은 분들을 위해 설명하자면
{data : userData}와 같은 디스트럭처링 문법은
객체의 속성 값을 새로운 변수에 할당할 때 사용하는 문법입니다.
즉 우리가 받아온 data 프로퍼티의 밸류값을 userData라는 새로운 변수를 만들어
그 변수 안에 할당해준다는 의미인것이죠!!
그런뒤 JSON.stringfy 메서드를 통해 화면에 데이터를 뿌려주는데
논리곱 단축평가를 이용해 useData가 존재할 때에만 화면에 값을 표시하게 합니다.
논리곱 단축평가는 논리합 단축평가와 달리 앞값이 트루시하면
뒷값이 무슨 값이든 뒷값을 반환하는 특징이 있어요!
반대로 falsy하면 falsy값이 반환됩니다.
🐶마치며
커스텀 훅만 보려고 했지만 어쩌다 보니
논리곱 단축평가와 객체 디스트럭처링까지 곁들여버린
맛있는 클론코딩이 되었네요
'react' 카테고리의 다른 글
리액트의 성능을 최적화 해보자 프로젝트 (0) | 2023.03.27 |
---|---|
라이프사이클 메서드 폼 미쳤다. (5) | 2023.03.21 |
useCallback을 케이크처럼 쉽게 먹는 방법 (0) | 2023.03.17 |
useMemo를 케이크처럼 쉽게 먹는 방법 (0) | 2023.03.13 |
useReducer를 케이크처럼 쉽게 이해하는 법 (1) | 2023.03.13 |