[Worksheet 220512] React Hook

방예서·2022년 5월 12일
0

Worksheet

목록 보기
30/47
React 맛보기

useState

Component

elements의 집합

useState

상태 값을 관리해주는 Hook
위의 코드에서 setState를 두고 요소가 변경될 때마다 다시 render 해주어야 하는 불편함이 있었는데, useState() 를 사용해서 쉽게 상태를 변경해준다.

useState는 [state 변수와 해당 변수를 갱신할 수 있는 함수] 이 쌍, 배열을 반환한다.

const [keyword, setKeyword] = React.useState(
          window.localStorage.getItem("keyword")
        );

useState 사용시, 이런 식으로 윈도우의 localstorage 에서 처음 값, 데이터를 가져올 때 render 하는데에 시간이 오래 걸릴 수 있다.

useState의 인자로는 무엇이든 들어올 수 있고, useState 인자로 함수로 초기화 시킴으로써 render 이후에 함수 내부의 코드가 실행될 수 있도록 해준다. (lazy initialize) 의도적으로 함수를 실행시킴으로써 delay를 걸어주는 것이다.

useEffect

side effect = 의도하지 않은 효과, 부수 효과

어떤 값이 변경될 때마다만 작동하는 함수를 독립적으로 쓰고 싶을 때 사용할 수 있다.
우리의 경우 초기값에서 keyword가 바뀔 때만 localstorage에 저장하는 함수가 실행되면 좋겠다. (부수적으로) 버튼을 누를 때도 localstorage가 실행되고... 하여튼 비효율적이다.

그래서 독립적인 공간에 원하는 코드를 넣고 실행할 수 있도록 한다.

React.useEffect(function, dependency array)

  • function : 부수적으로 일어났으면 하는 것.
    어떤 값이 변경될 때 실행할 함수

  • dependency array : 의도한 것.
    위에서 '어떤 값'. 배열로 여러 값을 지정해 줄 수도 있다. 이 값이 변화될 때 부수효과를 낸다.
    아예 값을 주지 않을 경우 모든 상황에서 함수를 실행한다.
    빈 배열로 둘 경우, 부수효과는 처음 한 번만 동작한다.

Custom Hook

use{Name}

useState, useEffect 같은 hook을 직접 커스텀해서 만들어보자.

		React.useEffect(() => {
          window.localStorage.setItem("keyword", keyword);
        }, [keyword]);

        React.useEffect(() => {
          window.localStorage.setItem("result", result);
        }, [result]);

keyword, result 각각 바뀔 때 독립적으로 저장하기 위해서는 이런 식으로 코드를 작성해야한다. 하지만 하는 일은 비슷한데, 코드의 중복이 우리를 불편하게 한다.

-> 커스텀 훅!

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Static Template</title>
  </head>
  <body>
    <script
      crossorigin
      src="https://unpkg.com/react@17/umd/react.development.js"
    ></script>
    <script
      crossorigin
      src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"
    ></script>
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
    <div id="root"></div>
    <script type="text/babel">
      const rootElement = document.getElementById("root");

	  // 우리가 원하는 이름으로 state를 만들고, 로컬스토리지에 넣어주는 함수
	  // value는 빈 문자열로 초기화
      function useLocalStorage(itemName, value = "") {
        const [state, setState] = React.useState(() => {
          // itemName 넣어주거나, 그 값이 없으면(처음이면) value 값 넣어주기
          // keyword, result는 처음에는 아무 값도 없기 때문에 
          // 인자에서 설정했던 "" 빈 문자열이 들어오고
          // typing은 state 만들어줄 때 false로 값을 넘겨주기 때문에 
          // default 값이 그것으로 설정된다.
          return window.localStorage.getItem(itemName) || value;
        });

        // 값이 변경될 때 로컬스토리지에 넣어주기
        React.useEffect(() => {
          window.localStorage.setItem(itemName, state);
        }, [state]);

        return [state, setState];
      }

      const App = () => {
        const [keyword, setKeyword] = useLocalStorage("keyword");
        const [result, setResult] = useLocalStorage("result");
        const [typing, setTyping] = useLocalStorage("typing", false);

        function handleChange(event) {
          setKeyword(event.target.value);
          setTyping(true);
        }
        function handleClick() {
          setTyping(false);
          setResult(`We find ${keyword}`);
        }

        return (
          <>
            <input onChange={handleChange} value={keyword} />
            <button onClick={handleClick}> search </button>
            <p> {typing ? `Looking for ${keyword}` : result} </p>
          </>
        );
      };

      ReactDOM.render(<App />, rootElement);
    </script>
  </body>
</html>


처음


버튼 누르기 전


버튼 누른 후

Hook flow

setState - prev

function handleClick() {
          setShow((prev) => !prev);
        }

setState 할 때 이전 값인 prev가 담겨있다.

Hook flow

Hook들의 호출 타이밍

!! 변화 발생시
-> render start 
-> useState 
-> render end 
    -> Child render start 
    -> Child useState 
    -> Child render end 
    -> Child useEffect (작성 순서대로) 
-> useEffect (작성 순서대로)

상태 값이 바뀌어 rerender 되면,
부모의 useEffect는 자식의 useEffect가 다 끝난 이후에야 동작한다.


  • useEffect
    render가 끝나고 동작
    자식이 있다면 자식의 useEffect 이후에 부모 useEffect

  • update 시
    어떤 값이 변경 될 때 useEffect clean up이 먼저 일어난 이후에 useEffect 동작 useEffect clean up -> uesEffect
    부모의 useEffect부터 clean up
    한번이라도 useEffect 등록됐으면 clean up, 처음에는 clean up X

  • dependency array
    전달 받은 갑스이 변화가 있는 경우에만. 작성 순서대로.

profile
console.log('bang log');

0개의 댓글