리액트. 다양한 hooks 만들어보기

PpOee·2020년 3월 15일
1

react. hooks

목록 보기
1/1
post-thumbnail
post-custom-banner

useEffect 란?

componentDidMount, componentWillUnMount, componentDidUpdate.

import React, { useState, useEffect } from "react";
import "./styles.css";

const useTitle = initialTitle => {
  const [title, setTitle] = useState(initialTitle);
  const update = () => {
    const html = document.querySelector("title");
    html.innerText = title;
  };
  useEffect(update, [title]);
  return setTitle;
};

const App = () => {
  const titleUpdate = useTitle("Loading...");
  setTimeout(() => titleUpdate("home"), 5000);
  return <div className="App">hi</div>;
};

export default App;

useEffect( ... ,[ a ] ) 란, a 값이 바뀔 때만 useEffect가 재실행 된다는 것.

5초 후에 titleUpdate("home") 로 인해 title 상태 값이 Loading... 에서 home으로 바뀐다.

title값이 바뀌면서 useEffect에 있는 update 함수가 재실행된다.

결과 :

5초 뒤에 < title > 텍스트 값이 Loading... 에서 home으로 바뀌는걸 볼 수 있다.


useRef 란?

document.getElementById

useRef() 로 생성할 수 있고 .current 속성으로 접근 가능하다.

(단, useRef 는 리렌더링을 발생시키지 않는다.)

import React, { useRef } from "react";
import "./styles.css";

const App = () => {
  const potato = useRef();
  setTimeout(() => console.log(potato.current), 5000);
  return (
    <div className="App">
      <input ref={potato} placeholder="la" />
    </div>
  );
};

export default App;

결과 :

위 코드에서는 5초 뒤에 potato가 참조하고 있는
< input placeholder="la" > 가 콘솔로 출력된다.


useTabs 만들어보기

import React, { useState } from "react";
import "./styles.css";

const content = [
  {
    tab: "Section 1",
    content: "Hi"
  },
  {
    tab: "Section 2",
    content: "Hi 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">
      {content.map((section, index) => (
        <button onClick={() => changeItem(index)}>{section.tab}</button>
      ))}
      <div>{currentItem.content}</div>
    </div>
  );
};

export default App;

useConfirm 만들어보기

import React from "react";
import "./styles.css";

const useConfirm = (message = "", callback) => {
  if (typeof callback !== "function") {
    return;
  }
  const confirmAction = () => {
    if (confirm(message)) callback();
  };
  return confirmAction;
};

const App = () => {
  const deleteWorld = () => {
    console.log("deleting the world");
  };
  const confirmDelete = useConfirm("Are you sure", deleteWorld);
  return (
    <div className="App">
      <button onClick={confirmDelete}>Delete</button>
    </div>
  );
};

export default App;

결과 :

버튼을 누른 뒤 "Are you sure?" 이라는 confirm 창이 뜨고, yes를 누르면 callback 인자로 들어간 deleteWorld 함수가 실행되어 "deleting the world" 라는 콘솔이 뜬다.


useBeforeLeave 만들어보기

페이지를 벗어나면 사용자에게 팝업?이나 알림을 띄워 사용자를 붙잡을 수 있는 useBeforeLeave

import React, { useEffect } from "react";
import "./styles.css";

const useBeforeLeave = onBefore => {
  if (typeof onBefore !== "function") {
    return;
  }
  const handle = () => {
    onBefore();
  };
  useEffect(() => {
    document.addEventListener("mouseleave", handle);
    return () => document.removeEventListener("mouseleave", handle);
  }, []);
};

const App = () => {
  const beg = () => console.log("plz don't leave");
  useBeforeLeave(beg);
  return <div className="App">hi</div>;
};

export default App;

useEffect 안의
return () => document.removeEventListener("mouseleave", handle);
componentWillUnMount 일땐 mouseleave 이벤트를 지우겠다는 의미

결과 :

마우스가 화면을 벗어나면 mouseleave 이벤트가 발생해서 handle이 실행되고 이로인해 onBefore인자로 들어온 beg 함수가 실행되어 "plz don't leave" 라는 문장이 콘솔에 출력된다.


useFadeIn 만들어보기

import React, { useRef, useEffect } from "react";
import "./styles.css";

const useFadeIn = (duration = 1, delay = 1) => {
  if (typeof duration !== "number" || typeof delay !== "number") {
    return;
  }
  const element = useRef();
  useEffect(() => {
    if (element.current) {
      element.current.style.transition = `opacity ${duration}s ease-in-out ${delay}s`;
      element.current.style.opacity = 1;
    }
  }, []);
  return { ref: element, style: { opacity: 0 } };
};

const App = () => {
  const fadeInH1 = useFadeIn(1, 2);
  const fadeInP = useFadeIn(10, 5);

  return (
    <div className="App">
      <h1 {...fadeInH1}>h1</h1>
      <p {...fadeInP}>pp</p>
    </div>
  );
};

export default App;

결과 :

h1은 2초 뒤에 1초 동안 서서히 나타나고, pp는 5초 뒤에 10초 동안 서서히 나타난다.


useScroll 만들어보기

사용자가 스크롤을 내릴 때 색상을 바꾼다던가 사용자가 알아차릴 수 있는 효과를 줄 때 사용할 수 있는 useScroll

import React, { useState, useEffect } from "react";
import "./styles.css";

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 state;
};

const App = () => {
  const { y } = useScroll();

  return (
    <div className="App" style={{ height: "1000vh" }}>
      <h1 style={{ position: "fixed", color: y > 100 ? "red" : "blue" }}>hi</h1>
    </div>
  );
};

export default App;

결과 :

처음 초기값(0, 0) 으로 파란색인 hi가 스크롤을 내리면 y 상태 값이 100을 넘어 hi가 빨간색이 된다.
( div에 1000vh 높이를 지정해준 이유는 스크롤을 만들기 위해서이다. )

post-custom-banner

0개의 댓글