본문 바로가기

React

React Hooks

반응형

React Hooks | NomardCoder

 

✅Check

 

useTitle = react document의 title을 몇개의 hooks와 함께 바꾸는 것

useInput = 그냥 input 역할을 한다

usePageLeave = 유저가 page를 벗어나는 시점을 발견하고 함수를 실행

useClick = 누군가 element를 클릭하는 시점을 발견

useFadeIn = 어떤 elemet든 상관없이 애니메이션을 elemet안으로 서서히 사라지게 만듦

useFullscreen = elemet든 풀스크린으로 만들거나 일반화면으로 돌아가게

useHover = 어떤 화면에 마우스를 올렸을 때 감지

useNetwork = online offline 상태 감지

useNotification = notification API사용할때 유저에게 알림을 보내줌

useScroll = 스크롤 사용할떄 감지

useTabs = 웹사이트에 메뉴 또는 무엇이든간 tab을 사용하기 쉽게 만들어줌

usePreventLeave = 유저가 변경사항이나 무엇이든간 저장하지 않고 페이지를 벗어나길 원할 때 확인

useConfirm = 어떤 기능이 존재하고

useAxios = HTTP request client axios를 위한 wrapper 같은 것

 

- 사람들이 다운받아 사용할 수 있도록 NPM에 올려보기 - npm package에 등록하는 방법을 배울 것

- codeSandBox에서 시뮬 돌려보고 VSC에 정리

 


 

✔ useState 

 

 

Using the State Hook – React

A JavaScript library for building user interfaces

ko.reactjs.org

 

 

useInput

 

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

const useInput = (initialValue, vaildator) => {
  const [value, setValue] = useState(initialValue);
  const onChange = (e) => {
    const {
      target: { value }
    } = e;
	
    //유효성검사
    let willUpdate = true;
    if (typeof vaildator === "function") {
      willUpdate = vaildator(value);
    }
    if (willUpdate) {
      setValue(value);
    }  
  };
  
  return { value, onChange };
};

const App = () => {
  const maxLen = value => value.length < 10;
  const name = useInput("hy", maxLen);
  return (
    <div className="App">
      <h1>Hello</h1>
      <input placeholder="name" {...name} />
    </div>
  );
};

export default App;

 

 

useTabs

 

import React, { useState } from "react";

const content = [
  {
    tab : "section1",
    desc : "i'm the content of the section 1"
  },
  {
    tab : "section2",
    desc : "i'm the content of the section 2"
  }
]

//useTab hook
const useTabs = (initialTab, allTabs) => {
  //에러확인하기) content없거나, 배열이 아닐때 return
  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((item, index) => 
        <button onClick={()=>{changeItem(index)}}>{item.tab}</button>
      )}
      <div>{currentItem.desc}</div>
    </div>
  )
}

export default App;

 

 

 

 ✔ useEffect 

 

 

Using the Effect Hook – React

A JavaScript library for building user interfaces

ko.reactjs.org

 

- useEffect는 componentDidMount, componentWillUnMount, componentDidUpdate

- 2개의 인자를 받음

(첫번째는 function으로서의 effect, 두번째는 dependency의 deps)

- deps가 있다면 effect는 deps 리스트에 있는 값일 때만 값이 변하도록 활성화된다.

- 계속해서 이벤트가 추가되는 것을 막아줌 ([ ])

 

 

 useTitle

- tab title을 바꿔주는 hook

 

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

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

}

const App = () => {
  const titleUpdater = useTitle("Loading...");
  setTimeout(()=>titleUpdater("home"), 3000)
  return (
    <div className="App">
      <h1>Hello</h1>
    </div>
  );
}

export default App;

 

 

✔ useRef 

- reference는 기본적으로 우리의 component의 어떤 부분을 선택할 수 있는 방법 -> document.getElementByID( )와 동등

- react에 있는 모든 component는 reference element를 가지고 있음 (reference prop)

 

 

useClick

 

import React, { useState, useEffect, useRef } from "react";

const useclick = onclick => {
  if(typeof onclick !== 'function'){
    return;
  }
  const element = useRef();
  useEffect(() => {
  	//useEffect가 mount, update 되었을 때
    if(element.current){
      element.current.addEventListener("click",onclick);
    }
    //useEffect componentWillUnMount시
    return () => {
      if(element.current){
        element.current.removeEventListener("click",onclick);
      }
    }
    //dependency없음 = (update시 고려해야할 사항 없음) = [ ]
  }, [])
  return element;
}


export default function App() {
  const say = () => console.log("say!!!!!say!!!!!")
  const title = useclick(say);
  return (
    <div className="App">
      <h1 ref={title}>Hello</h1>
    </div>
  );
}

 

- useEffect에 function을 넣으면, componentDidMount, componentWillUnMount 때 호출 됨 (dependency가 존재하지 않는 한)- dependency가 존재한다면, useEffect 안 function은 componentDidMount일 때만 호출 됨.

 

- function을 return 받았다면, 그 function은 componentWillUnMount로 부터 호출된 것.

 

*useEffect가 mount시, unmount시- componentWillUnMount 될 때,  addEventListener를 지워야한다-> useEffect는 componentDidMount상태에 동작함-> componentWillUnMount일 때 ,이벤트가 발생한 뒤 정리할 필요가 있음. => function을 return 시켜줌-> removeEventListener

 

 

useHover

 

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

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

const App = () => {
  const say = () => console.log("hover");
  const title = useHover(say);
  return (
    <div className="App">
      <h1 ref={title}>Hello</h1>
    </div>
  );
}

export default App;

 

- useClick과 비슷,  addEventListener의 event type을 click -> mouseenter로 변경

 


 

useConfirm & usePreventLeave

- 위 두개는 실제로 hook이 아니다. useState와 useEffect를 사용하지 않고 만들것이기 때문.

 

 

useConfirm

 

import React from "react";

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

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

export default App;

 

- confirmDelete가 실제로는 confirmAction과 같음

 

 

usePreventLeave

 

import React from "react";

const usePreventLeave = () => {
  const listener = (e) => {
    e.preventDefault();
    e.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">
      <button onClick={enablePrevent}>protect</button>
      <button onClick={disablePrevent}>unprotect</button>
    </div>
  );
};

export default App;

 

 


 

useBeforeLeave

 

import React, { useState, useEffect, useRef } from "react";

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

const App = () => {
  const desc = () => console.log("Don't leave me ㅠㅠ");
  useBeforeLeave(desc);
  return (
    <div className="App">
      <h1>Hello</h1>  
    </div>
  );
};

export default App;

 

 

useFadeIn

 

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

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 ${delay}s ease-in-out`;
      current.style.opacity = 1;
    }
  }, [])
   // return element;
  return {ref:element, style:{opacity:0}};
}


const App = () => {
  // const el = useFadeIn();
  const fadeInH1 = useFadeIn(2,1);
  const fadeInP = useFadeIn(2,2);
;  return (
    <div className="App">
	{/* <h1 ref={el} style={{opacity:0}}>Hello</h1> */}
      <h1 {...fadeInH1}>Hello</h1>
      <p {...fadeInP}>lorem brbrbr</p>
    </div>
  );
}

export default App;

 

- duration=1, delay=0은 기본 값

- hooks와 animation을 섞어보기

 

 

useNetwork

 

import React, { useState, useEffect, useRef } from "react";

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);
    () => {
      window.removeEventListener("online",handleChange);
      window.removeEventListener("offline",handleChange);        
    };
  },[]);
  return status;
};

const App = () => {
  const handleNetworkChange = onLine => {
    console.log(onLine ? 'we just went online' : 'we are offline');
  }
  const onLine = useNetwork(handleNetworkChange);
  return (
    <div className="App">
      <h1>{onLine ? 'onLine' : 'offLine'}</h1>
    </div>
  );
}

export default App;

 

- navigator가 online또는 offline 되는걸 막아준다. -> 확인시켜줌

 

 

useScroll

- 유저가 스크롤해서 무언갈 지나쳤을 때, 색상을 바꾸거나 무엇이든 해주는 기능 

 

import React, { useState, useEffect, useRef } from "react";

const useScroll = () => {
  const [state, setState] = useState({ x: 0, y: 0 });
  const onScroll = () => {
    setState({x:window.screenX, 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" }}>Hello</h1>
    </div>
  );
};

export default App;

 

 

useFullscreen

 

import React, { useState, useEffect, useRef } from "react";

const useFullscreen = callback => {
  const element = useRef();
  const triggerFull = () => {
    if(element.current){
      element.current.requestFullscreen();
      if(callback && typeof callback === 'function'){
        callback(true);
      };
    }
  };
  const exitFull = () => {
    document.exitFullscreen();
    if(callback && typeof callback === 'function'){
      callback(false);
    }
  };
  return { element, triggerFull, exitFull };
}

export default function App() {
  const onFulls = isFull => {
    console.log(isFull ? 'we are full' : 'we are small');
  }
  const { element, triggerFull, exitFull } = useFullscreen(onFulls);
  return (
    <div className="App" style={{height:'1000vh'}}>
      <div ref={element}>
      <img src="https://docs.microsoft.com/ko-kr/windows/uwp/design/controls-and-patterns/images/image_licorice.jpg"/>
      </div>
      <button onClick={triggerFull}>full btn</button>
      <button onClick={exitFull}>exit btn</button>
    </div>
  );
}

 

↓ 브라우저 호환성에 따른 Fullscreen API 

 

import React, { useState, useEffect, useRef } from "react";

const useFullscreen = callback => {
  const element = useRef();
  const runCb = isFull => {
    if(callback && typeof callback === 'function'){
      callback(isFull);
    }
  };
  //브라우저 호환성
  const triggerFull = () => {
    if(element.current){
      if(element.current.requestFullscreen){
        element.current.requestFullscreen();
        //firefox
      }else if(element.current.mozRequestFullScreen){
        element.current.mozRequestFullScreen();
        //opera
      }else if(element.current.webkitRequestFullscreen){
        element.current.webkitRequestFullScreen();
        //ms
      }else if(element.current.msRequestFullscreen){
        element.current.msRequestFullscreen();
      }
      runCb(true);
  }
};
  //브라우저 호환성
  const exitFull = () => {
    document.exitFullscreen();
    if(document.exitFullscreen){
        document.exitFullscreen();
        //firefox
      }else if(document.mozRequestFullScreen){
        document.mozCancelFullScreen();
        //opera
      }else if(document.webkitRequestFullscreen){
        document.webkitExitFullScreen();
        //ms
      }else if(document.msRequestFullscreen){
        document.msExitFullscreen();
      }
      runCb(false);
  };
  return { element, triggerFull, exitFull };
};

const App = () => {
  const onFulls = isFull => {
    console.log(isFull ? 'we are full' : 'we are small');
  }
  const { element, triggerFull, exitFull } = useFullscreen(onFulls);
  return (
    <div className="App" style={{height:'1000vh'}}>
      <div ref={element}>
        <img src="https://docs.microsoft.com/ko-kr/windows/uwp/design/controls-and-patterns/images/image_licorice.jpg"/>
      </div>
      <button onClick={triggerFull}>full btn</button>
      <button onClick={exitFull}>exit btn</button>
    </div>
  );
};

export default App;

 

 

useNotification

 

import React, { useState, useEffect, useRef } from "react";

const useNotification = (title, option) => {
  if (!("notification" in window)) {
    return;
  }
  const fireNotif = () => {
    if (Notification.permission !== "granted") {
      Notification.requestPermission().then((permission) => {
        if (permission === "granted") {
          new Notification(title, option);
        } else {
          return;
        }
      });
    } else {
      new Notification(title, option);
    }
  };
  return fireNotif;
};

const App = () => {
  const triggerNotif = useNotification("yaya");
  return (
    <div className="App">
      <button onClick={triggerNotif}>hello</button>
    </div>
  );
};

export default App;

 

 

Notification

Notifications API의 Notification 인터페이스는 사용자에게 데스크톱 알림을 설정하고 보여주는데 사용됩니다.

developer.mozilla.org

 

 

useAxios

- HTTP request를 만드는 것

- axios는 customization과 configuration을 허용

(ex) axios는 default URL을 설정하거나 자동으로 헤더를 설정하는 거 과 같은 것들을 허용함)

 

import React, { useState, useEffect, useRef} from "react";
import defaultAxios from 'axios';

const useAxios = (opts, axiosInstance = defaultAxios) => {
  const [state, setState] = useState({
    loading : true,
    error: null,
    data:null
  });
  if(!opts.url){
    return;
  };
  useEffect(() => {
    axiosInstance(opts).then(data => {
      setState({
        ...state,
        loading:false,
        data
      });
    }).catch(error => {
      setState({
        ...state,
        loading:false,
        error
      })
    })
  },[]);
  return state;
}

const App = () => {
  const { loading, error, data } = useAxios({url:"https://yts.mx/api/v2/list_movies.json"});
  console.log(loading, error, JSON.stringify(data));
  return (
    <div className="App">
      <h1>Hello</h1>
    </div>
  );
}

export default App;

 

- useEffect로 axios 부르기, dependency를 빈값으로 둬서 update로 부터 보호

- axios는 data를 성공적으로 받으면 then, error가 생기면 catch

'React' 카테고리의 다른 글

React에서 'onClick' Event 실행해보기  (0) 2020.12.09
Movie-app  (0) 2020.11.26
React Hooks 간단 예습  (0) 2020.11.07
Lifecycle Methods to Class  (0) 2020.11.05
react 추가 study  (0) 2020.11.04