09. Hook Flow

Hook이 동작하는 순서에 대해서 설명한다.

현재까지 배운 useEffect와 useState의 동작하는 순서에 대해서 말하겠다.

App render -> useState : initial -> rendering End -> useEffect : 등록한 순서대로

작동을 한다. 여기서 상기해야할 점은 useEffect는 사이드 이펙트를 관리하는 Hook이기 때문에 전부 그려지고 난뒤에, 작동을 하는 것을 알 수 있다.

flow chart

<body>
  <div id="root"></div>
  <script src="https://unpkg.com/react@16.12.0/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@16.12.0/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone@7.8.3/babel.js"></script>
  <script type="text/babel">
    // https://github.com/donavon/hook-flow

    function Child() {
      console.log('%c    Child: render start', 'color: MediumSpringGreen')

      const [count, setCount] = React.useState(() => {
        console.log('%c    Child: useState callback', 'color: tomato')
        return 0
      })

      React.useEffect(() => {
        console.log('%c    Child: useEffect no deps', 'color: LightCoral')
        return () => {
          console.log(
            '%c    Child: useEffect no deps cleanup',
            'color: LightCoral',
          )
        }
      })

      React.useEffect(() => {
        console.log(
          '%c    Child: useEffect empty deps',
          'color: MediumTurquoise',
        )
        return () => {
          console.log(
            '%c    Child: useEffect empty deps cleanup',
            'color: MediumTurquoise',
          )
        }
      }, [])

      React.useEffect(() => {
        console.log('%c    Child: useEffect with dep', 'color: HotPink')
        return () => {
          console.log(
            '%c    Child: useEffect with dep cleanup',
            'color: HotPink',
          )
        }
      }, [count])

      const element = (
        <button onClick={() => setCount(previousCount => previousCount + 1)}>
          {count}
        </button>
      )

      console.log('%c    Child: render end', 'color: MediumSpringGreen')

      return element
    }

    function App() {
      console.log('%cApp: render start', 'color: MediumSpringGreen')

      const [showChild, setShowChild] = React.useState(() => {
        console.log('%cApp: useState callback', 'color: tomato')
        return false
      })

      React.useEffect(() => {
        console.log('%cApp: useEffect no deps', 'color: LightCoral')
        return () => {
          console.log('%cApp: useEffect no deps cleanup', 'color: LightCoral')
        }
      })

      React.useEffect(() => {
        console.log('%cApp: useEffect empty deps', 'color: MediumTurquoise')
        return () => {
          console.log(
            '%cApp: useEffect empty deps cleanup',
            'color: MediumTurquoise',
          )
        }
      }, [])

      React.useEffect(() => {
        console.log('%cApp: useEffect with dep', 'color: HotPink')
        return () => {
          console.log('%cApp: useEffect with dep cleanup', 'color: HotPink')
        }
      }, [showChild])

      const element = (
        <>
          <label>
            <input
              type="checkbox"
              checked={showChild}
              onChange={e => setShowChild(e.target.checked)}
            />{' '}
            show child
          </label>
          <div
            style={{
              padding: 10,
              margin: 10,
              height: 30,
              width: 30,
              border: 'solid',
            }}
          >
            {showChild ? <Child /> : null}
          </div>
        </>
      )

      console.log('%cApp: render end', 'color: MediumSpringGreen')

      return element
    }

    ReactDOM.render(<App />, document.getElementById('root'))
  </script>
</body>
  • 위의 코드를 실행해보면 Hook Flow에 대해서 알 수 있는데, 렌더링시

    Parents render -> Parents useState Call -> Parents render end -> Child render -> child useState Call -> Child render end -> (Child useEffect clean up) -> Child useEffect -> (Parents useEffect clean up) -> Parents useEffect

    cleanup은 최초 렌더시 되지 않지만, 만약 변경사항이 존재할때에는 cleanup들이 먼저 발생을 하고 useEffect가 작동한다.

  • 또한, vue와 비슷하게 moutend 까지는 Parents Component가 먼저하지만, 그 이후로는 Child Component가 모든 과정이 끝나야 Parents의 UseEffect를 하는 것을 알 수 있다.

  • 이 부분에 대해서 다른 Hook을 공부하고 더 업데이트를 해야겠다.

08. Custom Hook

반복되는 Hook 들을 커스텀 된 훅으로 묶어서 사용하는 방식

  • 반복되는 로직을 재사용이 쉽도록 만들어서 사용하며, 커스텀 Hook을 만들 때에는 use라는 단어를 앞에 두어서 만들어준다.
import { useState, useCallback } from 'react';

function useInputs(initialForm) {
  const [form, setForm] = useState(initialForm);
  // change
  const onChange = useCallback(e => {
    const { name, value } = e.target;
    setForm(form => ({ ...form, [name]: value }));
  }, []);
  const reset = useCallback(() => setForm(initialForm), [initialForm]);
  return [form, onChange, reset];
}

export default useInputs;

< 출처 : 21. 커스텀 Hooks 만들기 · GitBook>

위와 같이 일련의 과정들을 하나의 Hook 함수로 만들어서 사용하면 된다.

이 커스텀 Hook은 많이 만들어보고 공통적인 과정을 하나의 함수로 바꾸는 연습을 해봐야할 것 같다.

07. Component Side Effect

useEffect를 통해서 변수의 상태를 변경 시킴으로 일어나는 사이드 이펙트를 관리하는 방법을 배웠다.

  • side-effect는 부정적인 의미로만 쓰이는 것이 아닌, 한 변수의 변화로 인해 함수 외부의 값이 변화하거나 일어나는 현상을 side-effect라고 한다.

  • useState의 초기값의 lazy한 inital을 필요로 할때에는 useState(()=>window.localStorage.getItem('initial')) 를 통해 가져올 수 있다.

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

  • useEffect라는 Hook은 update가 되었을 때, 특정작업을 하며, 컴포넌트가 mounted 됬을때와, unmount 되었을때 특정 작업을 처리할 수 있는 Hook이다.

  • 실례로, 뒤의 배열인 initial을 제거 하고, useEffect를 쓰면 최초 렌더링 시, 실행되는 것을 확인할 수 있다.

  • 용어를 정리하면, 뒤의 의존값에 들어가는 것을 deps, 그리고 return 되는 함수가 clenup

  • deps내의 의존성이 있을때에는 해당 의존성이 값이 변화할때 effect 내의 cleanup 후 useEffect내의 함수가 실행된다. (최초 렌더시에 useEffect가 실행된다.)

  • 만약 deps의 의존성이 빈배열일 때에는, 렌더시에만 실행이 된다.

  • 그리고 deps가 없을때에는 mounted 될때 useEffect가 실행이 되고, unmounted가 될때 cleanup이 실행이 된다.

  • 좀 더 자세한 설명은 밑의 링크를 보면 되고, 화면이 렌더링 되는 시점과 연관되어서는 더 공부를 해야겠다.

자세한 설명 : https://rinae.dev/posts/a-complete-guide-to-useeffect-ko

'기술공부 > React' 카테고리의 다른 글

[React] 09. Hook Flow  (0) 2021.12.23
[React] 08. Custom Hook  (0) 2021.12.23
[React] 06. Component State Handle  (0) 2021.12.16
[React] 05. event handler  (0) 2021.12.15
[React] 04. rerendring  (0) 2021.12.14

06. Component State Handle

함수형 컴포넌트에서는 컴포넌트 내부의 데이터를 사용하고, handle하기 위해서 useState라는 Hook을 사용한다.

  • useState를 사용하면, 현재의 원소상태와, 이 원소를 수정할 수 있는 setter가 주어진다.

    const [keyword, setKeyword] = React.useState("");
  • useState 안에 들어가 있는 값은 해당 value의 초기값에 해당된다.

  • 우리가 정한 setter를 통해 value를 수정할 수 있다.

  • setter를 사용하는 방법은 두 종류로, 새로운 value를 그대로 넣어주는 방법과, 함수를 넣어주는 방법이 있다.

  • 자세한 설명은 공식문서인 https://ko.reactjs.org/docs/faq-state.html 여기에 잘 설명되어 있다.

  • 새로운 value를 넣어주는 방식은 setState의 특성상 연속되는 state의 값 변경을 즉각적으로, 사용하지 못한다는 단점이 있다.

  • 왜냐하면 위의 공식설명서에서도 나와있듯이, state의 값은 즉각적으로 변화하는 것이 아니기 때문에, 이전 상태값을 가져오지 못하는 경우가 발생한다.

  • 그렇기 때문에, 과거의 값을 활용하여, 새로운 작업을 할때에는, 새로운 값을 바로 넣어주는 것보다, 함수를 통해 값을 변화시켜주는 것이 더 좋다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Static Template</title>
  </head>
  <script src="https://unpkg.com/react@17/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  <body>
    <div id="root"></div>
  </body>
  <script type="text/babel">
    const rootElement = document.querySelector("#root");
    const App = () => {
      const [count, setCount] = React.useState(0);
      function handleIncrease() {
        setCount((count) => count + 1);
      }

      function handleDecrease() {
        setCount(count - 1);
      }

      function handleDoubleIncrease() {
        handleIncrease();
        handleIncrease();
      }

      function handleDoubleDecrease() {
        handleDecrease();
        handleDecrease();
      }
      return (
        <div>
          <h1>{count}</h1>
          <button onClick={handleIncrease}>+</button>
          <button onClick={handleDoubleIncrease}>2+</button>
          <button onClick={handleDecrease}>-</button>
          <button onClick={handleDoubleDecrease}>2-</button>
        </div>
      );
    };
    ReactDOM.render(<App />, rootElement);
  </script>
</html> 
  • 위 코드를 실행해보면 알지만, 2번 연속으로 더해주는 것은 정상작동하는 것에 반해, 2번연속 값을 내리는 것은 작동안하는 것을 알 수 있다.

'기술공부 > React' 카테고리의 다른 글

[React] 08. Custom Hook  (0) 2021.12.23
[React] 07. Component Side Effect  (0) 2021.12.22
[React] 05. event handler  (0) 2021.12.15
[React] 04. rerendring  (0) 2021.12.14
[React] 03.JSX  (0) 2021.12.10

05. Event Handler

리액트에서는 이벤트를 처리하는 방식은 DOM Elements에서 처리하는 방식과 유사하다.

React에서는 소문자 대신 캐멀 케이스를 사용을 하며, jsx를 사용하여, 문자열이 아닌 함수로 이벤트 핸들러를 전달하면 된다.

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // 콜백에서 `this`가 작동하려면 아래와 같이 바인딩 해주어야 합니다.
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

ReactDOM.render(
  <Toggle />,
  document.getElementById('root')
);

위와 같이 jsx에서 () 를 사용하지 않고 할시에는 해당 메소드를 this에 바인딩을 하거나,

화살표 함수로 선언을 하거나 콜백에 화살표 함수를 사용하는 방법도 있다.

기본적으로 React에서는 DOM element와 동일하게 event 객체를 전달해주는데, 추가적으로 파라미터를 받고 싶으면

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

위와 같이 하면된다.

화살표함수를 통해, 전달해줄 id와 events를 명시적으로 나타내거나, bind를 통해 추가적인 인자를 추가하는 방법도 있다.

아직 컴포넌트를 통해 event를 전달하는 방식은 공부하지 않았지만, 이에 대해 공부하게 되면 추가적으로 작성하겟다.

React에서 지원하는 이벤트와 events 객체 안에 있는 값들이 궁금하면.

https://ko.reactjs.org/docs/events.html

위 링크를 통해 자세하게 읽으면 된다.

코드 출처: https://ko.reactjs.org/docs/handling-events.html

'기술공부 > React' 카테고리의 다른 글

[React] 07. Component Side Effect  (0) 2021.12.22
[React] 06. Component State Handle  (0) 2021.12.16
[React] 04. rerendring  (0) 2021.12.14
[React] 03.JSX  (0) 2021.12.10
[React] 02. Multi Element  (0) 2021.12.09

04 Reredering

react에서는 값이 변경이 되는 부분만 rerendering이 된다.

function tick() {
  const element = (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {new Date().toLocaleTimeString()}.</h2>
    </div>
  );
  // highlight-next-line
  ReactDOM.render(element, document.getElementById('root'));
}

setInterval(tick, 1000);

위와 같이 매 초마다 h2의 text 값이 변경되지만, 전체를 rerender 하는 것이 아닌 실제 값이 변경된 부분에만 변경이 일어난다.

diff 알고리즘에 대해서는

https://ko.reactjs.org/docs/reconciliation.html

에 자세하게 설명이 되어있다.

memo, useMemo, useCallback으로 React 성능 최적화하기 :: Code Playground

위의 글처럼 react의 성능향상을 위해선 Hook에 대해서 더 공부해야할 것 같다.

'기술공부 > React' 카테고리의 다른 글

[React] 06. Component State Handle  (0) 2021.12.16
[React] 05. event handler  (0) 2021.12.15
[React] 03.JSX  (0) 2021.12.10
[React] 02. Multi Element  (0) 2021.12.09
[React] 01. React.CreateElement  (0) 2021.12.08

03. JSX

  • jsx는 슈가 문법으로 javascript를 확장한 문법이다.

  • React에서 javascript로 마크업을 만들고, 시각적으로 좀 더 수월하게 표현하게 해주는 방법이다.

  • JSX는 필수는 아니지만, UI 관련 작업을 할 때 도움이 된다.

  • JSX는 HTML 태그를 넣을수 있을 뿐만 아니라,

그렇기 때문에, jsx 내부에 jsx를 사용해서 만들 수 있다.

단 jsx를 활용한 태그는 파스칼케이스로 만들것을 권장한다.

그 이유는 첫글자가 대문자가 아니라면, 기존의 HTML 태그로 인식할 수 도 있기 때문이다.

const Paint = ({title, description, children}) => {
    return (
    <>
        <h1>{title}</h1>
        <h3>{children}</h3>
           {children}
    </>
)
}


const element = (
    <>
        <Paint title ="Good" description = "good">
            {Paint({title : "Bad" , description="bad" children="hi"} )}
        </Paint>
    </>
)

이렇듯 jsx 내부에 jsx를 쓸수도 있으며, 더 나아가, javascript 문법을 활용해서 return 된 jsx를 활용해서 만들수 도 있다.

'기술공부 > React' 카테고리의 다른 글

[React] 06. Component State Handle  (0) 2021.12.16
[React] 05. event handler  (0) 2021.12.15
[React] 04. rerendring  (0) 2021.12.14
[React] 02. Multi Element  (0) 2021.12.09
[React] 01. React.CreateElement  (0) 2021.12.08

02. Multi Element

React.createElement('div',{
    children : [
    React.createElement("h1",null,'first'),
    React.createElement("h3",null,'second'),
    React.createElement("h5",null,'third')
]
})


///

React.createElement(
      "div",
      null,
      React.createElement("h1", null, "first"),
      React.createElement("h3", null, "second"),
      React.createElement("h5", null, "third")
    );

///

jsx 처럼
<div> 
  <h1>first </h1>
  <h3>second</h3>
  <h5>third</h5>
</div>

위와 같은 방식으로 하나의 요소 안에 여러개의 children 을 만들 수 있다.

하지만 위와 같은 방법의 문제점은 쓸데 없는 div를 감싼다는 문제가 있다.

그렇기 때문에 React에서는 Fragment라는 tag를 지원한다.

React.createElement(React.Fragment,{
    children : [
    React.createElement("h1",null,'first'),
    React.createElement("h3",null,'second'),
    React.createElement("h5",null,'third')
]
})


///

React.createElement(
      React.Fragment,
      null,
      React.createElement("h1", null, "first"),
      React.createElement("h3", null, "second"),
      React.createElement("h5", null, "third")
    );

///

jsx
<Fragment> 
  <h1>first </h1>
  <h3>second</h3>
  <h5>third</h5>
</Fragment>

Fragment를 사용하면, 쓸데없는 div 없이 자식들을 렌더링 할 수 있다.

jsx와 React.createElement를 통해, 하나의 컴포넌트 안에 다수의 자식을 만드는 법을 배웠다.

그리고, 그 자식들이 div로 감싸지는 것이 싫으면 React에서 제공해주는 Fragment 태그를 사용해서 감싸주면 된다.

'기술공부 > React' 카테고리의 다른 글

[React] 06. Component State Handle  (0) 2021.12.16
[React] 05. event handler  (0) 2021.12.15
[React] 04. rerendring  (0) 2021.12.14
[React] 03.JSX  (0) 2021.12.10
[React] 01. React.CreateElement  (0) 2021.12.08

+ Recent posts