Level 2: react-subway-map 학습 로그

동동·2021년 6월 23일
1

0. PR 링크

1. What the heck is a 'SIDE EFFECT'?

React에는 함수형 컴포넌트는 없고, 함수 컴포넌트만 있다. 함수 컴포넌트는 함수형 프로그래밍에서 말하는 순수함수가 아닙니다.

순수함수의 정의는 다음과 같습니다.

  1. 동일한 인자를 함수에 입력하면, 항상 같은 결과가 반환된다.
  2. 함수는 부수효과(side effect)를 가지고 있지 않다.
  1. The function return values are identical for identical arguments (no variation with local static variables, non-local variables, mutable reference arguments or input streams).
  2. The function application has no side effects (no mutation of local static variables, non-local variables, mutable reference arguments or input/output streams).

함수 컴포넌트에서는 부수효과가 발생합니다. 가장 많이 사용되는 useState, useEffect hook 모두 부수효과를 일부러 일으킵니다.
useState의 경우, 인스턴스화 되지 않아 상태를 가질 수 없는 함수 컴포넌트에 closure를 사용하여 의도적으로 함수외의 변수에 값을 할당하는 부수효과를 일으킵니다. 또한, useEffect는 아예 이름에서부터 대놓고 말하고 있습니다. SIDE EFFECT는 여기서 만들라고! hooks이 도입된 React 16.8 이후 함수 컴포넌트는 더이상 순수하지 않습니다.

함수 컴포넌트에서 side effect는 정확히 무엇일까요? 이를 반대로 말하자면, 함수 컴포넌트의 원래 기능은 무엇일까요? 함수의 본래의 목적은 인자를 받아서 어떠한 연산을 수행한 후 값을 반환하는 것입니다. 함수 컴포넌트는 인자(props)를 받아서 어떠한 연산 혹은 로직을 수행한 후 jsx.element, 즉 유저에게 보여질 view(UI)를 반환한다고 할 수 있습니다.
그렇다면, 함수 컴포넌트에 있어서 side effect는 유저에게 보여지는 view, 반환되는 UI에 반영되지 아니하는 모든 로직이라고 할 수 있을 것 같습니다.

예를 한 번 들어보겠습니다. Redux에서 관리 중인 state는 아래와 같습니다.

"state": {
  "status": "idle",
  "entries": []
}

비동기 로직에 따라 status"idle" ➡ "loading" ➡ "done" 로 변경되고 있습니다. status"done" 일 때 window.alert로 유저에게 알림을 주고 싶습니다.

여기서 window.alert는 side effect일까요?

아니면 UI로 보아 side effect가 아닌 걸까요?

// ver1: window.alert를 side effect로 보아 useEffect 에서 실행
const StatusNotification = () => {
  const status = useSelector((state) => state.status);
  const entries = useSelector((state) => state.entries);

  useEffect(() => {
    if (status === "done") {
      window.alert("done");
    }
  }, [status]);

  return (
    <div>
      <span>Current Status: {status}</span>
      <span>Entries Length: {entries.length}</span>
    </div>
  );
};


// ver2: window.alert를 UI의 일부로 보아 함수 컴포넌트 본문에서 실행
const StatusNotification = () => {
  const status = useSelector((state) => state.status);
  const entries = useSelector((state) => state.entries);

  if (status === "done") {
    window.alert("done");
  }

  return (
    <div>
      <span>Current Status: {status}</span>
      <span>Entries Length: {entries.length}</span>
    </div>
  );
};

제 생각에 window.alert는 전형적인 side effect입니다.
window.alert의 경우, DOM에 영향을 주지 않으며 유저와의 interaction에 interrupt를 발생시키기 때문입니다.

왜 side effect인지 여부가 중요할까요? 인자가 동일할 때 반환값이 일정하다는 것은, React가 rendering의 제어권을 가지고 언제 어떻게 rendering을 하여도 UI로서는 문제가 없다는 뜻입니다. 하지만 함수 컴포넌트 내부에 side effect가 있으면 React가 rendering을 언제 어떻게 하는지에 따라 UI가 바뀔 수 있습니다. 그렇기에 React는 side effect를 발생시키는 모든 로직을 useEffect hook에 사용하게끔 강제하여 dependencies가 변경된 경우에만 side effect를 실행시켜 컴포넌트 rendering을 trigger하려고 하는 것입니다.

사실 위의 ver2도 큰 문제가 없을 수 있습니다. 하지만, StatusNotification의 부모 컴포넌트의 type이 변경되거나 entries가 변경되는 등 StatusNotification의 re-rendering이 촉발된다면, 매 rendering 될 때마다 window.alert가 발생하게 될 것이고, 이는 명백히 개발자가 의도한 바가 아닐 것입니다.

2. autocomplete attribute

  • autocomplete는 text 또는 numeric value를 받는 <input>, <textarea>, <select>, <form> 에서 사용가능한 attribute입니다.

  • 브라우저는 보통 유저들이 form을 채우는 걸 돕는 기능이 있는데, autocomplete attribute는 브라우저들에게 form 채우기 기능에 대한 힌트를 제공합니다.

  • 일반적으로 form 채우기 기능은 브라우저에 따라 상이합니다. 과거에 유저가 입력한 값을 바탕으로 브라우저가 자동으로 값을 채워줄 수도 있고, 유저가 설정해둔 값으로 채워줄 수도 있습니다. 또한 신용카드 정보 등에 대해서는 자동완성 전에 authentication 절차를 취할 수도 있습니다.

  • 일반적으로 브라우저는 자동완성을 제공하기 위해 아래의 조건을 요구할 수 있습니다.

    <input>/<select>/<textarea> 는

    1. name 또는 id attribute가 있어야 한다.
    2. <form>의 자식이어야 한다
    3. 부모<form>submit 버튼을 가지고 있어야 한다.
  • "on", "off", "name", "email", "username", "organization" 등의 값을 가질 수 있습니다. 회원가입, 로그인 폼에서 자주 사용되는 아래의 두가지 값에 대해서 살펴보겠습니다.

    • "new-password": 새로운 패스워드를 의미하므로, 회원가입 창의 <input type="password" />에서 사용하여야 합니다. 그렇지 않다면, 브라우저가 기존 비밀번호로 자동완성해버릴 수 있습니다. 또한, 요즘 브라우저는 매우 높은 보안 수준의 비밀번호를 제안해주기도 합니다.
    • "current-password": 현재 패스워드를 의미한다. 로그인 창에서는 "current-password"를 사용하면 기존 비밀번호로 브라우저가 자동완성해줄 수 있습니다.

https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete

https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute

profile
작은 실패, 빠른 피드백, 다시 시도

0개의 댓글