# Dream Coding - React 4. Habit Tracker ## ==4.1 리액트 전반적인 개념 정리 (class vs function component)== ### Class Component - state 와 lifecycle method를 가지고 있다. - `render` 함수의 return을 통해서 JSX를 반환 - 다음과 같은 단점이 있어서 Hook을 이용한 Function Component에 밀렸다 1. class is difficult : 객체 지향 언어를 사용해본적 없는 웹 개발자들에게 어려움 2. `this` binding issue : `this` 를 이용해서 항상 선언해야하는 불편함과 binding issue 3. we want functional programming! : 함수형 프로그래밍이 대세로 떠오름 4. code duplication : 너무 세세하게 lifeCycle이 쪼개져있어서 code가 중복됨 ### Function Component - state와 lifecycle method가 없다. (그래서 Stateless Component 라고 부르기도 함) - 그러나 **React Hook** 이 등장하면서 state와 lifecycle method를 사용할 수 있게 됨 - `return` 를 통해 JSX를 반환 ### 그래서 뭘 배워야 하는데? - Facebook 에서는 앞으로 새로 작성하는 컴포넌트들은 Function + Hook 로 작성할 것을 권유 - 그러나 기존의 클래스 컴포넌트들을 굳이 함수형 컴포넌트로 리팩토링 X ⇒ 따라서 둘다 배워야 함 ## ==4.2 템플릿 프로젝트 만들기== - `public` 폴더 : 정적 파일들 (static) - `src` 폴더 : 동적 파일들 (dynamic) - `nocript` 태그 (HTML) : 사용자가 자바스크립트를 돌리지 않을 경우 표시해주는 메세지 ⇒ 그래서 React를 사용하는 경우 큰 고려 X ## ==4.5 JSX 정리 (HTML 차이점 정리)== ### JSX Javascript를 HTML처럼 쓸 수 있게 만들어진 것 - class ⇒ className - javascript 비지니스 로직 { } - 한 Component안에서 return (render) 되는 JSX Node 는 **오직 1개**여야 함 ⇒ 불필요한 `<div>` 태그로 묶는것보다는 `React.Fragment` or <> </>를 이용하는 것이 좋음. ### 논리연산자 활용 [조건부 렌더링 - React](https://ko.reactjs.org/docs/conditional-rendering.html) - expr1 && expr2 expr1을 true로 변환할 수 있는 경우 expr2을 반환하고, 그렇지 않으면 expr1을 반환합니다. - expr1 || expr2 expr1을 true로 변환할 수 있으면 expr1을 반환하고, 그렇지 않으면 expr2를 반환합니다. ## ==4.7 State 이해하기== ### synthethic event 1. **CamelCase** 를 이용함 ```jsx <button onClick={()=>{console.log("Hello Potato!")}}> Activate Lasers </button> ``` 2. 외부 함수를 넘겨줄때 **`()` 를 명시하지 않음** ```jsx <button onClick={activateLasers}> Activate Lasers </button> ``` 3. 인자를 넘겨주고 싶다면 **Arrow Function을 이용**해서 넘겨줄것 (단, event 객체는 자동으로 넘어감) ```jsx <button onClick={(event)=>this.handleclick(event,this.potato)}> Click me </button> ``` ### state - `this.setState` 를 이용해서 변경해야함 - `this.state.count++` 등의 **직접 state를 변경하는 것은 위험함**! - **immutability** 를 지킬 것 ## ==4.7.1 보충설명 (Props에 대해서)== ### props [Dream Coding](https://academy.dream-coding.com/courses/take/react-basic/texts/16722247-4-7-1-props) - props는 props를 받은 하위컴포넌트에서 **절대 변경하면 안 됨** - 변경하고 싶다면, props를 준 컴포넌트에서 변경하도록 해야함 - 하위 컴포넌트에서 굳이 변경하고 싶다면, 상위 컴포넌트에서 props를 변경할 수 있는 콜백함수를 제공해서 실행시켜야 함. ⇒ 이걸 **State 끌어올리기 (State up)** 이라 함 - 이를 **단방향으로 데이터가 흐른다** 라고 표현 ## ==4.8 Habits 컴포넌트 (State up, list key)== ### 배열 컴포넌트 (Array Component) - 자식 Component에는 반드시 구별할 수 있는 `key` 값이 있어야 함. - 불필요한 리렌더링 방지 - `key` 값은 반드시 고유해야함 (배열의 index 값을 넣지 말 것) ## ==4.9 이벤트 처리하기 part2. State 업데이트 함수들 구현하기== ### immutablity - react에서는 직접적으로 state로 변경해서는 안 된다. - object 역시 안의 요소를 수정하는 식으로 해서는 안 된다 - re-rendering을 결정짓도록 comparision을 `shallow comparision` 으로 진행하기 때문! ⇒ 변수의 reference (주소값) 만 비교함! - immutability를 지키기 위해서는 **재할당 method**를 사용하거나, **spread operator를 사용해서 재할당**을 해주는 편이 좋다. ex) immutability를 지키지 못한 예제 ```jsx // bad this.setState(({user})=>{ user=newUser; }; // bad this.setState({idList}=>{ idList.push(newId); } ``` ex) immutability를 잘 지킨 예제 ```jsx // Object good => Using Object.assign this.setState((prevState)=>{ return Object.assign({},prevState,{user:newUser}); }; // Object good => using spread properties this.setState(({user})=>{ return { ...this.state, user: newUser, }; }; // Array good => using Array.concat this.setState(({idList})=>{ return { ...this.state, idList : this.state.idList.concat(newID), } } // Array good => using spread properties this.setState(({idList})=>{ return { ...this.state, idList : [...this.state.idList,newId], }; } ``` ## ==4.12 Add Form 만들기 (Refs 이용)== ### ref 개념 - JSX 요소를 참고할 수 있게 하는 개념 (Vanila 에서 Element 객체를 반환하는 method와 동일) ### ref 선언 - `inputRef = React.createRef();` ### ref 지정 ```jsx <input ref={this.props.inputRef} type="text" name="" id="newHabit" className="add-input" /> ``` ### ref 활용 - `const newHabit = this.inputRef.current.value`; ## ==4.14 중요 개념== ### components ### `state`, `render()` => re-render ### Virtual Dom - 변경된 부분만 html에 반영 - html이 많이 변한다면, react를 제대로 사용하지 않다는 것! - 잘 변경되는지 확인하기 위해서 chrom 의 react debuggin extenstion을 사용하는 것을 추천 ## 4.15 PureComponent활용 ### PureComponent - component에서 `shouldComponentUpdate()` 가 자동으로 구현되어 있는 것 - 목적은 props가 실제로 변경되지 않았을때도, VDOM에서 re-render을 진행하는 것을 방지 - `shallow comparison` 을 이용해서 props의 변경 여부를 check 함 ### Immutability - props를 받는 하위컴포넌트의 re-render가 생각한 대로 동작하지 않을때 (immutability를 못 지킨 경우), 해결할 수 있는 방법 2가지 1. 바뀌는 부분만 따로 떼서 props로 전달 2. `this.setState` 에서 아예 새로운 Object를 할당 ⇒ deconstructing을 이용하면 편함 ( call by value 형식으로 복사하기 때문) ## ==4.16 lifecycle 함수들 이해하기== > **1. 컴포넌트의 생명주기** [https://ko.reactjs.org/docs/react-component.html#the-component-lifecycle](https://ko.reactjs.org/docs/react-component.html#the-component-lifecycle) - **생명주기 (LifeCycle) : 컴포넌트의 생성부터 소멸까지의 과정** - 전체 생명주기는 다음과 같다 [https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/](https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/) ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/93f3274e-c15a-4063-a480-7cc2270a0430/Untitled.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/93f3274e-c15a-4063-a480-7cc2270a0430/Untitled.png) - 자주 사용되는 생명주기는 다음과 같다 ### **render( )** - `render()` 메서드는 클래스 컴포넌트에서 **반드시 구현**되어야 하는 유일한 메서드 - **데이터가 변경**되어 **새 화면**을 그려야 할 때 자동으로 호출되는 함수 - 당연히 함수이기에, **반환값은 오직 1개**여야함 ⇒ 만약 여러개를 반환하고 싶다면, 의미 없는 최상위 노드를 추가해서 묶거나, Fragment를 이용 ⇒ 자세한 사항은 [이곳](https://www.notion.so/329538f9a30c4b9ba173b3655e3b8ad9) 참고 - 반환되는 것 - **JSX** 를 반환 (**React Element**) - 배열을 반환 (**Fragment**) - **Portal** ### **constructor(props)** - **맨 처음에 생성될 때 한번만 호출** - **state를 선언**하거나 **이벤트 처리 method를 바인딩**할때 사용 - 만약 이 작업이 없다면 호출하지 않아도 됨 - `setState()` 를 **호출하면 안 됨 ⇒ 생성자는 유일하게 `this.state`를 직접 할당할 수 있는 곳** ```jsx constructor(props) { super(props); // 여기서 this.setState()를 호출하면 안 됩니다! this.state = { counter: 0 }; this.handleClick = this.handleClick.bind(this); } ``` ### **componentDidMount()** - **컴포넌트가 마운트** 된 직후 호출 - 즉 **render() 함수가 호출** 된 이후 호출 ### **componentDidUpdate(prevProps, prevState, snapshot)** - **갱신이 일어난 직후 호출** ⇒ 최초 렌더링에서는 호출되지 않음 - **컴포넌트 갱신이후 DOM을 조작**하기 위해서 이 메서드를 활용 - **이전과 현재의 props를 비교하여 네트워크 요청**을 보내는 작업도 이 메서드를 활용 ### **componentWillUnmount()** - **컴포넌트가 소멸되기 직전**에 호출되는 함수 - **컴포넌트에서 감시하고 있는 작업들을 해제**할 때 필요한 함수 ex) setInterval 함수가 사용 됨 → clearInterval 로 여기서 해제 - 해제 작업이 생략되면, 메모리 누수 현상 (Memory Leak)이 발생할 수 있음 --- 위의 5가지 생명주기 함수들은 결국 다음과 같이 작동한다. ``` constructor() -> render() -> componentDidMount() (생성) render()-> componentDidUpdate() (갱신=> 이 과정은 반복될 수 있음) componentWillUnmount() (소멸) ``` ## ==4.17 function 컴포넌트, memo 정리== ### VSC Component shorcut `rcc` : for class `rsi` : for fuction ### 함수형 컴포넌트의 활용 및 특징 - this를 쓰지 않아도 됨 - pure Componet ⇒ `React.memo` 이용 `const Add = memo(~~~)`; - `render` 함수 ⇒ `return`으로 대체 ## 4.18 React Hook ### `useState` - `this.state` 와 `this.setState` 와 유사한 Hook library - 사용하기 위해선 ```jsx import React, { useState } from 'react'; ``` - 사용방법 ```jsx const [value, setValue] = useState(0); ``` 1. `useState(param)` 의 parameter : **value의 초깃값 설정** 2. `useState(param)` 의 반환 값 : 배열 - 첫 번째 요소 ⇒ **관리할 value** - 두 번째 요소 ⇒ **value를 관리할 수 있는 함수** ( `this.setState()` ) 와 유사 ) - 단, setState와 달리 **대체함(replace)** - 보통은 위의 예시 코드와 같이 비구조화 할당을 통해 변수에 할당함 - 주의점 - `setValue` 를 쓴다고 **즉각적으로 바뀌지 않음** - 따라서 즉각적으로 무언가를 반영해야 한다면 **callback function**으로 넘겨야함 ```jsx setPhotoUri(() => { navigation.navigate('Result', { photoUri: newUri, }); return newUri; }); ``` - Array나 Object의 경우 `setValue` 에서 반드시 **immutable** 하게 넘겨줘야함 (수정 메서드 사용) ⇒ Destructor operator 를 사용 ( `[...]` ) ### `useEffect` - [LifeCycle](https://www.notion.so/Component-state-Life-Cycle-in-class-component-c97ebc03131d42fd92b97b267d594517) 에서 `componentDidMount`, `componentDidUpdate` 를 대체 - Component가 **re-render 될때마다 호출** - 즉 React 컴포넌트가 **화면에 렌더링된 이후에 비동기로 처리되어야 하는 부수적인 효과**들을 흔히 **Side Effect**라 부르는데, 이 Side Effect를 처리하기 위한 함수 - 사용하기 위해선 ```jsx import React, { useEffect } from 'react'; ``` - 사용 방법 ```jsx useEffect(() => { console.log('렌더링이 완료되었습니다!'); },[]); ``` 1. useEffect() 의 첫번째 parameter : rendering이 될때 **실행시킬 함수** - 이 함수의 **반환 값으로 뒷정리 (clean-up) 코드**를 넣어줄 수 있음 - `componentWillUnmount` 와 비슷한 효과, 단 **useEffect 가 실행될때 마다** (즉 랜더링이 될 때마다) 뒷정리 코드는 실행됨 ```jsx useEffect(() => { console.log('effect'); console.log(name); return () => { console.log('cleanup'); console.log(name); }; }); ``` 2. useEffect() 의 두번째 parameter : **배열** - 배열 안의 **요소가 바뀔 때만** 실행 , 배열 안의 요소는 `useState()` 로 지정한 변수나 `props` - **빈 배열** ⇒ `componentDidMount` 일 때만 실행 ```jsx useEffect(() => { console.log('마운트 될 때만 실행됩니다.'); }, []); ``` - **무언가 있는 배열** ⇒ 그 변수가 바뀔때만 실행 ```jsx useEffect(() => { console.log(name); }, [name]); // name이 바뀔때만 실행됨 ``` ### `useRef` - Reference를 저장하기 위한 Hook `const spanref = useRef();` ### `useCallback` - 함수를 저장하기 위한 Hook `const handleIncre = useCallback(()=>{});` ### 함수형 컴포넌트의 주의점 - 함수형은 전부 반복해서 호출된다. (class는 render만 다시 호출) - 따라서 props로 전달하고 싶은 변수는 전부 Hook을 사용하여 기억을 해야한다. - Object로 변수들을 묶을때 정말로 연관되어 있는지 깊게 생각해봐야 함. - 싹다 단일 데이터로 관리하면 코드가 지저분해지고 - Object로 묶다보면 Hook이 제대로 동작하지 않는다.