스터디/React

[Hooks] 실전형 리액트 Hooks

_leezoee_ 2022. 5. 17. 17:04

(오..npm에 본인들이 만든 hooks을 공유하는 개발자들이 굉장히 많다..

영상에서 니꼬쌤도 실제로 npm에 자신이 만들어 쓰는 hooks을 공유할거라고 했고, 나도 npm upload를 해보고싶다.)

 

https://nomadcoders.co/react-hooks-introduction/lectures/1586

 

All Courses – 노마드 코더 Nomad Coders

초급부터 고급까지! 니꼬쌤과 함께 풀스택으로 성장하세요!

nomadcoders.co

저번에 노마드코더의  리액트 기초와 NextJS를 완강했으니 이번엔 실전형 리액트 Hooks 에 대해 들어보고자 한다.

이것도 역시 무료강의.

 


code sendbox 에서 실습

 

useState

const [item, setItem] = useState(1); //명시
<h1> { item } </h1> //사용

 

hooks이 나오기 전에는 this. 나 return 등으로 사용했었는데 hooks 이 나오고는 그런거 신경 안써줘도됨! 

const App = () => {
    const [item, setItem] = useState(1);
    const incrementItem = () => setItem(item + 1);
    const decrementItem = () => setItem(item - 1);
    return (
    	<div className = "App">
            <h1>Hello {item}</h1>
            <h2>Start editing to see some magic happen !</h2>
            <button onClick={incrementItem}>Increment</button>
            <button onClick={decrementItem}>Decrement</button>
       </div>
    );
}

 

useInput

기본적으로 input을 변경.

const useInput = (initialValue) => { 
    const [value, setValue] = useState(initialValue);
    const onChange = event => {
    	console.log(event.target);
    }
    return { value, onChange };
};

const App = () => {
	const name = useInput("Mr.");
    return (
    	<div className="App">
            <h1>Hello</h1>
            <input placeholder="Name" {...name}/>
        </div>
    );
}

요기에 validation 코드 넣어보기 => value의 길이 제한 해보기

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>Hello</h1>
            <input placeholder="Name" {...name}/>
        </div>
    );
}

 

useTabs

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

 


useEffect

기존 componentDidMount, componentDidUpdate, componentWillUnMount 역할 수행

useEffect(함수, [ dependency] );//dependency 가 바뀔때마다 실행.

한번만 실행 시키고 싶다면

useEffect(함수, [ ] );  //dependency 비워놓으면 됨.

 

 

 

useTitle

제목을 업데이트 하는 hooks 만들어보기

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"), 3000); //3초뒤에 타이틀 바뀌도록 테스트코드넣음.
    return (
        <div className = "App">
             <div>Hi...</div<
        </div>
    );
};

 

 

useClick

reference는 기본적으로 component의 어떤 부분을 선택할 수 있는 방법.

( document.getElementById()를 사용한것과 동등 )

//useRef() 사용예제.
const App = () => {
    const potato = useRef();
    setTimeout(() => potato.current.focus().3000);//3초뒤에 포커싱.     
    return(
        <div className="App">
        	<div>Hi</div>
            <input ref={potato} placeholder="test"/>
        </div>
    );
}
//useClick() 사용예제.
const useClick = onClick => {
    if(typeof onClick !== "function"){
       return;
    }
    const element = useRef();
    useEffect(() => {
        if(element.current) {//존재여부확인
          element.current.addEventListener("click", onClick);
        }
        return () => {//componentWillUnMount 때 호출.
          if(element.current) {
              element.curren.removeEventListener("click", onClick);
          }
        };
    }, []);//dependency 없음. componentDidMount 때 한번만 실행되라는 의미.
    return element;
}

const App = () => {
    const sayHello = () => console.log("say hello");
    const title = useClick();
    return(
        <div className="App">
        	<h1 ref={title}>Hi</h1>
        </div>
    );
}

 

 

useConfirm & usePreventLeave

 

//useConfirm : 사용자가 무엇을 하기 전에 확인.
const useConfirm = (message = "", onConfirm, onCancel) => {
   if(!onConfirm && typeof onConfirm !== "function ") {//onConfirm 함수가 명시되어있지않거나, 함수가 아닐때
      return; 
   }
   if(!onCancel && typeof onCancel !== "function ") {
      return;
   }
   const confirmAction = () => {
      if(confirm(message)){
         onConfirm();
      } else {
         onCancel();
      }
   };
   return confirmActions;
};

const App = () => {
    const del = () => console.log("Delete");
    const abort = () => console.log("Aborted");
    const confirmDelete = useConfirm("Are you sure?", del, abort);
    
	return (
        <div className = "App">
           <button onClick={confirmDelete}>Delete</button>
        </div>
    );
};
//usePreventLeave
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">
            <button onClick={enablePrevent}>Protect</button>
            <button onClick={disablePrevent}>UnProtect</button>
        </div>
    );
};

 

 

useBeforeLeave

탭을 닫을 때 실행되는 function

const useBeforeLeave = (onBefore) => {
    if(typeof onBefore !== "function"){
       return;
    }
    const handle = (event) => {
       const {clientY} = event;
       if(clientY <= 0) {
          onBefore();
       }       
    }
    useEffect(() => {
       document.addEventListener("mouseleave",  handle);//component가 Mount 되었을때
       return () => document.removeEventListener("mouseleave",  handle);//component가 Mount되지 않았을때
    }, []);
};

const App = () => {
  const begForLife = () => console.log("Pls don't leave");
  useBeforeLeave(begForLife);
  return(
    <div className="App">
       <h1>Hello</h1>
    </div>
  );
};

 

 

useNotification

브라우저 알람 실행하는 api 가져와 써보기

notificaton API

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

cosnt App = () => {
    const triggerNotif = useNotification("Hello World!", {body : "Welcome"});
    return(
        <div>
            <button onClick={triggerNotif}>Noti</button>
        </div>
    );
};

 

 

useAxios

axios : HTTP request를 만들때 씀.

axios를 add dependency 해줌.(npm 설치와 비슷)

 

//useAxios.js
import defaultAxios from "axios";

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(() => {//trigger 버튼 누를때마다 refetch하도록 구현
        axiosInstance(opts).then(response => {
           setState({
               ...state,
               loading : false,
               data
           });
        }).catch(error => {
           setState({...state, loading : false, error});
        });
    }, [trigger]);
    
    return {...state, refetch};
};
export default useAxios;



//index.js
...
const App = () => {
    const { loading, data, refetch } = useAxios({url : "https"://어쩌고"});
    console.log(`Loading : ${loading}\nError : ${error}\nData : ${JSON.stringfy(data)}`);
    
    return(
        <div>
           <h1>{data && data.status}</h1>
           <h2>{loading && "Loading"}</h2>
           <button onClick={refetch}>
               Refetch
           </button>
        </div>
    );
}
...