리액트에서 변수가 아니라 state를 사용하는 이유
리액트에서 변수를 사용하여 변경된 값을 렌더할 수 없기 때문에 state를 사용한다.
리액트에서 렌더하는 방법
render 함수를 통해 렌더링한다. render 함수는 컴포넌트가 어떻게 생겼는지 정의하는 역할을 한다. render함수는 view가 어떻게 생겼고 어떻게 작동하는지 객체를 반환()하고 컴포넌트에서 state를 업데이트 했을 때 새로운 state를 가지고 render함수를 다시 호출하여 보여지게 된다.
render함수를 다시 호출하면 새로운 view가 생성되고 이때 바로 DOM에 반영하지 않고 이전의 DOM과 비교하여 변경된 부분만 업데이트한다.
render함수는 JSX로 구현되어 있다.
render함수가 반환하는 것
JSX란
최신 문법을 ES5로 변환 해주는 바벨을 사용하여 DOM에 반영하기 위해 JSX를 자바스크립트 문법으로 변환한다.
virtual DOM vs DOM
DOM(Document Object Model)는 HTML,Javascript,CSS로 생성되는 것들을 말한다. DOM에 변화가 생기면, RenderTree를 재생성하고 그러면 모든 요소들의 스타일이 다시 계산된다. 또한, 레이아웃을 만들고 스타일 적용 하는 과정이 다시 반복한다.
복잡한 페이지는 DOM조작이 많이 발생하여 변화를 적용하기 위해 브라우저가 많은 연산을 필요로 하고, 전체적으로 비효율적으로 만든다.
VirtualDOM을 사용하면 변경된 부분만 자동으로 DOM에 전달하여 브라우저 내에서 발생하는 연산을 줄여 성능 개선이된다.
불변성을 하는 이유
렌더링 과정
1. setState를 호출 혹은 부모로부터 props를 새로 전달 받는다.
2. 렌더되기 전에 shouldComponentUpdate에서 false를 리턴하면 렌더되지 않고 true를 리턴하면 렌더한다.
3. Virtual DOM과 실제 DOM을 비교해서 변경사항이 있으면 다시 렌더한다.
리액트 생명주기에서 shouldComponentUpdate를 통해서 업데이트가 되었으면 리렌더링하고(true) 업데이트 되지 않으면 리렌더링하지 않는 것(false)을 알 수 있다.
state와 props의 이전값과 이후값을 어떻게 알 수 있을까?? 그 이유는 불변성에 있다. props와 state는 객체로 되어 있어 원본을 변하게한다. 그래서 원본을 유지하기 위해 즉, 불변성을 유지시키기 위해 spread 및 setState를 사용하여 불변성을 유지하여 이전값과 이후값을 알 수 있게되어있다.
함수 컴포넌트와 클래스 컴포넌트 차이점
함수형 컴포넌트는 라이프사이클이 없는데 클래스 컴포넌트보다 더 선호하는 이유는 첫번째로 클래스 컴포넌트는 props를 재사용한다. 여기서 재사용의 의미는 타임아웃이 지나기전에 props가 바뀐 유저로 변경되어 출력한다는 의미이다. 클래스 컴포넌트에서 시간이 흐르기 전에 어떤 동작 및 이벤트 발생 시 props를 재사용하기 때문에 개발자의 예상과 다르게 동작할 수 있는 문제점이 존재한다. 리액트에서 어떤 state와 props 값을 유지해야되는지 잘 확인해야한다.
만약 특정 render에 종속된 것 말고 가장 최근의 state나 props를 읽고 싶다면 어떻게 해야될까? 클래스에서는 this가 변할 수 있는 값이기 때문에 그냥 this.props, this.state를 읽어오면 된다. 리액트가 알아서 이를 처리해준다. 하지만 함수형 컴포넌트에서도 this처럼 변할 수 있고 서로 다른 render들끼리 공유할 수 있는 ref를 사용 this처럼 변경 가능하게 사용할 수 있다. 이벤트 value값을 받아와서 ref의 current에 대입하여 현재 값을 읽어올 수 있다.
두번째 장점으로 메모리 자원을 덜 사용한다.
https://codesandbox.io/s/class-vs-functional-3wvfu
https://boxfoxs.tistory.com/395
순수함수
함수형 프로그래밍에서 중요한 핵심은 외부의 상태에 영향을 받으면 안된다. 즉, 함수는 입력을 받고 출력을 반환함에 있어 외부의 값에 접근하지 않아야한다. 입력이 같을 때, 출력이 같아야 한다.
/* pure function */
const double = num => (num * 2);
/* impure function */
const operand = 2;
const multiple = num => (num * operand);
double 함수는 2를 입력하면 반환하는 값은 항상 4이지만, multiple은 operand라는 변수에 의해 2를 입력하면 항상 4를 반환하는지 알 수 없다. 만약 operand를 변경하게되면 2를 입력해도 4를 반환하는지 예상할 수 없다. 만약, multiple 함수에 의해 operand의 값이 변경되어도 순수 함수가 아니다.
순수함수와 리액트
자식 컴포넌트를 함수 내부라 하고 부모를 외부라고 한다면 자식 컴포넌트는 props를 바꾸지 못하여 순수함수의 성질을 지녔다고 할 수 있고 이는 컴포넌트의 실행을 예측하기 위해 의도된 것이다. 그리고 리액트에서는 한방향으로 데이터가 부모 컴포넌트에서 자식 컴포넌트로 흐르는 특징을 지녔는데 이것도 순수함수와 같은 맥락으로 볼 수 있다. 이벤트 발생 시 함수 호출만하고 있고 부모의 값을 변경하지 않아 순수함수라고 볼 수 있다.
함수형 프로그래밍
순수 함수를 사용함으로써 불변성을 지향하기 때문에 프로그램의 동작을 예측하기 쉬워지고 SideEffect를 없앨 수 있다. 높은 수준의 추상화(어떤 기능에 대해 어떻게 동작하는지 모르더라도 사용자가 할 수 있다.)가 가능하여 기능 사용이 편리해진다. 또한, 함수 단위의 코드 재사용이 더욱 쉬워진다. 이 말은 객체지향 프로그래밍에서 최소 단위가 "객체"이지만 함수형 프로그래밍은 이보다 작은 단위인 "함수"로 구현되어 있고 동작에만 집중되어 있어 상속없이 필요한 부분에 가져다 사용할 수 있다. 하지만 작은 단위의 함수를 넓은 범위로 재사용하게 된다면 프로그램의 복잡성이 증가되기 때문에 이를 방지하기위해 순수 함수라는 제약으로 함수를 구성해야 된다.
고차 컴포넌트
고차 컴포넌트 사용할 때는 조건을 체크하여 렌더링하는 컴포넌트를 달리 하고 싶을 때에도 사용할 수 있다. 예를들어 로그인이 되었을 때에는 사용자 프로필 아이콘과 로그아웃을 표시하고 로그인이 되지 않은 상태에서는 로그인과 회원가입을 표시할 수 있다.
https://developer-alle.tistory.com/301
First-class citizen
함수형 프로그래밍 언어 함수들은 전부 객체이다. 함수는 function 객체이다. 함수를 변수에 할당할 수 있고 함수를 파라미터로 넘길 수도 있고 함수를 반환 가능한 것을 first-class citizen이라고 한다.
고차함수(HOF)
고차함수는 함수를 인자로 받거나 또는 함수를 반환함으로써 동작하는 함수를 말한다. 배열의 reducer, filter, map 등이 있다.
고차컴포넌트(HOC)
리액트에서 동일한 패턴이 반복적으로 발생했을 때 한 곳에서 정의하고 많은 컴포넌트에서 로직을 공유할 수 있게하는 고차 컴포넌트를 사용하면 효율적이다. 컨테이너는 구독 및 state 같은 것을 관리하고 UI 렌더링 같은 것을 처리하는 컴포넌트에 props를 전달하고 고차 컴포넌트는 컨테이너를 그 컴포넌트 중 일부에 사용하고 있습니다. 고차 컴포넌트는 매개변수화된 컨테이너 컴포넌트 정의로 생각할 수 있습니다.
명령형 프로그래밍 vs 선언형 프로그래밍
Red Lobster
명령형 방식(HOW) : "12번 테이블 자리가 비어있습니다. 나와 우리 가족은 저 자리로 걸어가 앉을 것입니다."
선언형 방식 (WHAT) : "네 명 앉을자리를 부탁해요"집에 돌아가는 법
명령형 방식 (HOW) : 주차장 북쪽 출구를 나와 왼쪽으로 가세요. 12번가 출구에 도착할 때까지 15번 북쪽 도로를 타세요. 이케아를 끼고 우회전하세요. 직진하여 첫 번째 신호등에서 우회전 하세요. 다음 신호등을 지나 좌회전을 하세요. 우리 집은 #298입니다.
선언형 방식 (WHAT) : 내 주소는 98 West Immutable Alley, Eden, Utah 84310입니다.
명령형 프로그래밍(어떻게) : 어떻게 자리에 앉을지에 관심이 있다. 따라서 어떻게 자리에 앉을지에 대한 단계를 하나하나 나열해야 한다.
선언형 프로그래밍(무엇을) : 무엇을 원하는지에 더 집중되어 있다.
위 예시들을 통해 "그럼 자리에 앉는 방법은 누가 알고 있지?","주소만 알고 있다고 해서 집에 어떻게 돌아가지?"라는 질문이 생길 수 있을 것 같습니다. 사실 선언형 방식이 제대로 동작하기 위해서는 명령형으로 "어떻게"가 구현된 것들이 추상화되어 있어야 한다.
출처: https://boxfoxs.tistory.com/430 [박스여우 - BoxFox]
함수형 프로그래밍은 선언형 프로그래밍의 패러다임을 함수를 사용하여 구현하는 것이다. 이처럼 장점만 있는 것은 아니다. 여기서 발생하는 대표적인 것은 성능 문제를 따져봐야한다. filter와 map를 사용하면 전체 배열을 순회하기 때문에 성능 상 손해가 발생할 수 있다. 그래서 함수형 프로그래밍도 상황에 따라 적재적소에 잘 사용해야한다.
Hook 규칙
1. 최상위에서만 Hook을 호출해야 한다. 반복문, 조건문 혹은 중첩된 함수 내에서 Hook을 호출하면 안된다.
2. 오직 React 함수 내에서 Hook을 호출해야 한다.
useState