리액트 hook

Ahyeon, Jung·2024년 1월 18일
0

리액트 hook

리액트 hook의 등장 배경

  1. 상태 관리나 생명주기 메서드를 사용하기 위해서는 클래스 컴포넌트 안에 많은 코드를 작성해야 했기 때문에, 컴포넌트의 가독성이 떨어지고 유지보수하기 어려움

  2. 클래스 컴포넌트에서는 this 키워드를 사용해야 하기 때문에, 코드 작성 시 바인딩 문제로 혼란스러움

클래스형 컴포넌트의 이러한 문제점으로 리액트 16.8 버전에서 hook이 추가됨

함수형 반응형 프로그래밍

순수 함수와 데이터 스트림을 사용하여 시간에 따른 시스템 동작을 설명하는 데 중점을 두는 프로그래밍 패러다임
사용자 입력과 같이 데이터가 생성되는 대로 처리하고 시스템 전체에 변경 사항을 자동으로 전파하는 반응형 프로그래밍을 강조
FRP에서는 일반적으로 시간이 지남에 따라 새로운 값을 방출하는 데이터 스트림인 옵저버와 이러한 데이터 스트림의 변경에 반응하는 옵저버로 작업

노마드 코더 실전형 리액트 Hooks

useState

useInput

const useInput = (initialValue, validator) => {
  const [value, setValue] = useState(initialValue);
  const onChange = e => {
    const { target: { value }
    } = e;
    let willUpdate = true;
    if (typeof validator === "function") {
      willUpdate = validator(value);
    }
    if (willUpdate) {
      setValue(value);
    }
  };

  return { value, onChange };
};

useTabs

const useTabs = (initialTab, allTabs) => {
  if (!allTabs || Array.isArray(allTabs)) {
    return;
  }
  const [currentIndex, setCurrentIndex = useState(initailTab);

return { 
  currentItem: allTabs[currentIndex], 
  changeItem: setCurrentIndex  
  };
};

useEffect

useTitle

const useTitle = initialTitle => {
  const [title, setTitle] = useState(initialTitle);
  const updateTitle = () => {
    const htmlTitle = document.querySelector('title');
    htmlTitle.innerText = title;
  };
  
  useEffect(updateTitle, [title]);
  return setTitle;
};

useClick

const useClick = (onClick) => {
  if (typeof onClick !== "function"){
    return;
  }
  const element = useRef();
  
  useEffect(() => {
    if (element.current) {
      element.current.addEventListener("click", onClick);
    }
    return () => {
      if (element.current) {
        element.current.removeEventListener("click", onClick);
      }
    };
  }, []);
  return element;
};

useConfirm & usePreventLeave

const useConfirm = (message, callback, rejected) => {
  if (typeof callback !== "function" || typeof rejected !== "function") {
    return;
  }
  const confirmAction = () => {
    if (confirm(message)) {
      callback();
    } else {
      rejected();
    }
  };
  return confirmAction;
};
const usePreventLeave = () => {
  const listner = (event) => {
    event.preventDefault();
    event.returnValue = "";
  };
  const enablePrevent = () => {
    console.log("enablePrevent");
    window.addEventListener("beforeunload", listner);
  };
  const disablePrevent = () =>
    window.removeEventListener("beforeunload", listner);
  return { enablePrevent, disablePrevent };
};

useBeforeLeave

const useBeforeLeave = (onBefore) => {
  const handle = (event) => {
    const { clientY } = event;
    console.log(clientY);
    if (clientY < 0) onBefore();
  };

  useEffect(() => {
    document.addEventListener("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 = () => {
  const [status, setStatus] = useState(navigator.onLine);
  const handleChange = () => {
    console.log("handle chage");
    setStatus(navigator.onLine);
  };
  console.log("useNetwork", navigator.onLine);
  useEffect(() => {
    window.addEventListener("online", handleChange);
    console.log("online");
    return () => window.removeEventListener("online", handleChange);
  }, []);
  return status;
};

useScroll & useFullscreen

const useScroll = () => {
  const [state, setState] = useState({ x: 0, y: 0 });
  const onScroll = (event) => {
    setState({ y: window.scrollY, x: window.scrollX });
  };
  useEffect(() => {
    window.addEventListener("scroll", onScroll);
    return () => {
      window.removeEventListener("scroll", onScroll);
    };
  }, []);
  return state;
};
const useFullScreen = () => {
  const element = useRef();
  const triggerFul = () => {
    if (element.current) {
      console.log(element);
      element.current.webkitRequestFullscreen();
    }
  };
  return { element, triggerFul };
};

useNotification

const useNotification = (title, options) => {
  if (!("Notification" in window)) {
    return;
  }
  const fireNoti = () => {
    if (Notification.permission !== "granted") {
      Notification.requestPermission().then((permission) => {
        if (permission === "granted") {
          new Notification(title, options);
        } else {
          return;
        }
      });
    } else {
      console.log("aaa");
      new Notification(title, options);
    }
  };
  return fireNoti;
};

useAxios

const useAxios = (opts, axiosInsntance = 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());
    console.log("refetch", Date.now());
  };
  useEffect(
    () => async () => {
      await axiosInsntance(opts)
        .then((response) => {
          setState({
            loading: false,
            error: null,
            data: JSON.stringify(response)
          });
        })
        .catch((error) => {
          setState({
            ...state,
            error: error
          });
        });
    },
    [trigger]
  );
  return { ...state, refetch };
};
export default useAxios;
profile
https://a-honey.tistory.com/

0개의 댓글