✅ 비구조화 할당, 구조 분해
: event를 다른 함수로 분리할 수 있다. Ex) 이벤트를 분리한 파일, 다른 entity에 연결하여 처리할 수 있음.
const useInput = (initialValue) => {
const [value, setValue] = useState(initialValue);
return { value };
};
const App = () => {
const name = useInput("Mr.");
return (
<div className="App">
<h1>Use Hooks</h1>
<input placeholder="What's your name?" {...name} />
<input placeholder="What's your name?" value={name.value} />
</div>
);
};
=> useInput이 반환하는 모든 것을 ...name을 통해 풀어준다.(packing/unpacking)
💯💯💯 객체의 비구조화 할당
const { newValue } = e;
const newValue = e.newValue;
// e의 속성인 target: {value}가 존재하고
// target의 속성인 value를 변수 value에 할당한다.
const { target: { value }, } = e;
const value = e.target.value;
=> e객체의 속성인 newValue를 추출하여, 변수 newValue에 할당하는 것.
💯💯💯 배열의 비구조화 할당
const [newValue] = e;
=> e배열의 첫번째 요소를 추출하여, 변수 newValue에 할당하는 것.
✅ useState는 배열을 return 한다.
const item = useState("Start")[0];
const setItem = useState("Finish")[1];
=> 배열의 값을 하나만 사용하고 싶은 경우 다음과 같이 useState를 custom한다.
✅ useInput(초기값, 유효성 검사 function) → useState를 커스텀
const useInput = (initialValue, validator) => {
const [value, setValue] = useState(initialValue);
const onChange = (event) => {
const {
target: { value },
} = event;
let willUpdate = true;
if (typeof validator === "function") {
willUpdate = validator(value);
}
if (willUpdate) {
setValue(value);
}
};
return { value, onChange };
};
const App = () => {
const maxLen = (value) => {
value.length <= 10;
};
const name = useInput("Mr.", maxLen);
return (
<div className="App">
<h1>Use Hooks</h1>
<input placeholder="What's your name?" {...name} />
</div>
);
};
=> useInput의 두 번째 매개변수는 함수로, validator라는 함수명을 지어둔다.
✅ useTabs(초기값, 배열) → useState를 커스텀
const content = [
{
tab: "Section 1",
content: "I'm the content of the Section 1",
},
{
tab: "Section 2",
content: "I'm the content of the Section 2",
},
];
const useTabs = (initialTab, allTabs) => {
if (!allTabs || !Array.isArray(allTabs)) {
return;
}
const [currentIndex, setCurrentIndex] = useState(initialTab);
return {
currentItem: allTabs[currentIndex],
changeItem: setCurrentIndex,
};
};
const App = () => {
const { currentItem, changeItem } = useTabs(0, content);
return (
<div className="App">
<h1>Use Hooks</h1>
{content.map((section, index) => (
<button onClick={() => changeItem(index)}>{section.tab}</button>
))}
<div>{currentItem.content}</div>
</div>
);
};
=> useTabs가 첫 번째 매개변수로 초기값을 입력받고 두 번째 매개변수로 배열을 입력받아, 객체를 return한다.
객체의 첫 번째 속성은 currentItem이고, 두 번째 속성은 changeItem이다.
💯💯💯
const [ 상태, 상태변경함수 ] = useState(초기값);
currentItem: 배열의 현재 index, changeItem: 배열의 index를 변경하는 함수.
✅ useEffect는 ComponentDidMount, ComponentWillUnMount, ComponentDidUpdate로 이루어진다.
1. ComponentDidMount
2. ComponentDidUpdate
3. ComponentWillUnMount
✅ useTitle(초기값) → useEffect를 커스텀
const useTitle = (initialTitle) => {
const [title, setTitle] = useState(initialTitle);
const updateTitle = () => {
const htmlTitle = document.querySelector("title");
htmlTitle.innerText = title;
};
useEffect(updateTitle, [title]);
return setTitle;
};
const App = () => {
const titleUpdater = useTitle("Loading...");
setTimeout(() => titleUpdater("Home"), 5000);
return (
<div className="App">
<h1>Use Hooks</h1>
</div>
);
};
=> 상태변경함수를 return 함.
✅ useClick(함수) & useHover
useEffect(() => {
if (typeof onClick !== "function") return;
if (element.current) {
element.current.addEventListener("click", onClick);
}
return () => {
if (element.current) {
element.current.removeEventListener("click", onClick);
}
};
}, []);
=> 컴포넌트가 unMount될 때, useEffect에서 함수를 return한다. (cleanup)
💯💯💯
이벤트를 추가한 뒤 동일한 이벤트핸들러로 삭제를 해줘야 한다.
✅ useConfirm & usePreventLeave
: useState와 useEffect를 사용하지 않는다.
const useConfirm = (message = "", onConfirm, onCancel) => {
if (!onConfirm || typeof onConfirm !== "function") {
return;
}
if (onCancel && typeof onCancel !== "function") {
return;
}
const confirmAction = () => {
if (window.confirm(message)) {
onConfirm();
} else {
onCancel();
}
};
return confirmAction;
};
=> !onConfirm, onCancel을 검사하는 이유?? 더 공부하기~~ 함수형 프로그래밍에 대한 이해!!!
kill everything
✅ useConfirm & usePreventLeave
: useState와 useEffect를 사용하지 않는다.
const usePreventLeave = () => {
const listener = (event) => {
event.preventDefault();
event.returnValue = "";
};
const enablePrevent = () => window.addEventListener("beforeunload", listener);
const disablePrevent = () =>
window.removeEventListener("beforeunload", listener);
return { enablePrevent, disablePrevent };
};
const App = () => {
const { enablePrevent, disablePrevent } = usePreventLeave();
return (
<div className="App">
<h1>Use Hooks</h1>
<button onClick={enablePrevent}>Protect</button>
<button onClick={disablePrevent}>Unprotect</button>
</div>
);
};
✅ useBeforeLeave
const useBeforeLeave = (onBefore) => {
if (typeof onBefore !== "function") return;
const handle = (event) => {
const { clientY } = event;
if (clientY <= 0) onBefore();
};
useEffect(() => {
document.addEventListener("mouseleave", handle);
return () => {
document.removeEventListener("mouseleave", handle);
};
}, []);
};
✅ useFadeIn & useNetwork
const useFadeIn = (duration = 1, delay = 0) => {
if (typeof duration !== "number" || typeof delay !== "number") return;
const element = useRef();
useEffect(() => {
if (element.current) {
const { current } = element;
current.style.transition = `opacity ${duration}s ease-in-out ${delay}s`;
current.style.opacity = 1;
}
}, []);
return { ref: element, style: { opacity: 0 } };
};
const useNetwork = (onChange) => {
const [status, setStatus] = useState(navigator.onLine);
const handleChange = () => {
if (typeof onChange === "function") {
onChange(navigator.onLine);
}
setStatus(navigator.onLine);
};
useEffect(() => {
window.addEventListener("online", handleChange);
window.addEventListener("offline", handleChange);
return () => {
window.removeEventListener("online", handleChange);
window.removeEventListener("offline", handleChange);
};
}, []);
return status;
};
✅ useScroll & useFullscreen
const useScroll = () => {
const [state, setState] = useState({
x: 0,
y: 0,
});
const onScroll = () => {
setState({ x: window.scrollX, y: window.scrollY });
};
useEffect(() => {
window.addEventListener("scroll", onScroll);
return () => window.removeEventListener("scroll", onScroll);
}, []);
return {
x: state.x,
y: state.y,
};
};
✅ useNotification
const useNotification = (title, options) => {
if (!("Notification" in window)) {
return;
}
const fireNotif = () => {
if (Notification.permission !== "granted") {
Notification.requestPermission().then((permission) => {
if (permission === "granted") {
new Notification(title, options);
} else {
return;
}
});
} else {
new Notification(title, options);
}
};
return fireNotif;
};
✅ useAxios
axios: http request이다. axios client를 받는다.(axios Instance)
Instance: 사용자가 http 통신할 때 커스텀하여 request를 보내고 싶을 때 사용하는 것.
const useAxios = (opts, axiosInstance = defaultAxios) => {
const [state, setState] = useState({
loading: true,
error: null,
data: null,
});
const [trigger, setTrigger] = useState(0);
if (!opts.url) {
return;
}
const refetch = () => {
setState({ ...state, loading: true });
setTrigger(Date.now());
};
useEffect(() => {
axiosInstance(opts)
.then((data) => {
setState({ ...state, loading: false, data });
})
.catch((error) => {
setState({ ...state, loading: false, error });
});
}, [trigger]);
return { ...state, refetch };
};
✅ 추가적으로...
useContext, useReducer, useCallback, useMemo
=> useContext, useReducer를 활용한 번역 라이브러리
=> useCallback, useMemo를 활용한 컴포넌트 최적화
'인강 > 노마드코더' 카테고리의 다른 글
[노마드코더] React Hooks (0) | 2024.02.15 |
---|---|
[노마드코더] React 클론코딩 movie-app (0) | 2024.01.11 |
[노마드코더] HTML, CSS, JavaScript 클론코딩 chrome-app (0) | 2023.12.19 |