08/25, redux(1)

Ian·2020년 8월 25일
0

Today I Learned

목록 보기
7/40
post-thumbnail

CheckPoint Solution

JSX 내에서 JS 변수를 사용하는 방법

<div>Hello, {name}</div> 과 같은 식으로 중괄호(curly bracket) "만"을 사용해주어야 한다.

JS의 문법인 Template literal${name} 과는 명확히 다르게 보아야 한다.

Props 에 대해서

정의는 React 에서 사용하는 부모 → 자식 간의 컴포넌트 순으로 내려받는 속성이다. 속성을 적어보자면 우선 일단 불변적(immutable) 이다. 그리고 클래스 컴포넌트와 함수 컴포넌트에서 전부 사용 가능하다. 그리고 한 개만이 아니라 여러가지 props 를 내려줄 수 있다. 그리고, export / import 를 통해 변수 이름을 변경하여 내보내고 받는 그런 과정처럼 별도의 변수명과 같이 호출하는 이름을 설정해서 내려보낼 수 있다.

클래스 컴포넌트와 함수 컴포넌트의 차이점

  • 클래스 컴포넌트는 life cycle method 를 의도적으로 명시하여 사용할 수 있으나, 함수 컴포넌트는 의도적으로 명시하여 사용할 수 없다. (예를 들자면 render 는 생명주기 메서드로 함수나 클래스에서 전부 사용이 가능하나, componentDidMount 와 같은 메서드는 함수 컴포넌트에선 사용할 수 없고 클래스 컴포넌트에서"만" 사용할 수 있다는
  • 클래스 컴포넌트는 state 를 사용 가능하나, 함수 컴포넌트는 사용할 수 없다.
  • 클래스 컴포넌트는 React.Component 로 부터 상속을 받으나, 함수 컴포넌트는 상속받지 않는다.

Life Cycle Method (API)

componentDidMount, componentDidUpdate, componentWillUnmount, 그리고 render 까지 대표적인 Life Cycle Method 들이다. 유의사항이 있다면, componentDidRender 와 같은 생명주기 메서드는 존재하지 않는다.

추가 : 해당 도식이 그려져있는 웹사이트를 참조해도 좋다.

React Lifecycle Methods diagram

Lifting state up

부모 컴포넌트의 state 를 바꾸어 주는 함수를 만들고(setState() 가 포함이 되어야겠지), bind 를 해줌 → 그리고 그 함수를 props 로 자식 컴포넌트에 내려줌 → 그 다음, 이제 자식 컴포넌트에서 그것을 받은 뒤 함수를 조건 하에 실행시켜 부모 컴포넌트의 state 를 변경해준다.

render() 안에서 setState() 를 실행하게 된다면?

무한루프가 걸린다. Maximum Update Depth exceeded 오류가 발생한다. 그 이유는 setState() 가 실행이 되면 상태가 바뀌기 때문에 자동으로 다시 컴포넌트가 render() 되는데, render() 를 할 때 setState() 를 통해 상태를 변경한다면 무한루프가 걸릴 수 밖에 없다. 렌더링을 하는데 상태가 바뀌고, 그래서 다시 렌더링을 한 번 더 하고, 그런데 또 상태가 바뀌어서 다시 렌더링을 하는 상황이 발생한다.

React 측에서는 해당 오류 구문이 생기기 전에 블락을 해버리는데, 만약 이것이 실행이 되어버린다면 call stack error 등의 오류가 발생할 것이다.

fetch 를 통해 데이터를 불러오는 과정은 언제 사용해야하는가?

생성주기 메서드인 componentDidMount 부분에서 사용해야 한다.

추가 : 생성자 (constructor) 에서도 fetch 를 통해 데이터를 불러올 수 있을까?

안 된다. 왜냐면 fetch 는 비동기적인 데이터를 불러오는 방식인데 constructor 는 동기적으로 클래스를 생성하는 코드이기 때문에 불가능하다. 데이터를 불러오기 전에 그 데이터에 의존해서 무언가를 만들려는 상황은 불가능하기 때문에 불가능하다.

fetch 는 비동기적으로 요청을 하게되는데, constructor 를 통해 클래스를 생성하는 과정에서 어떤 데이터를 가져오는데 걸리는 시간보다 먼저 그 데이터(fetch 를 통해 가져온)를 사용하려고 하게 되면 오류가 날것이라고 생각했습니다. - 황대성 님

추가 : 그러면 render 에서는 fetch 를 통해 데이터를 불러올 수 있을까?

안 된다. 그 이유는 위에 나와있는 render 에서 setState() 를 통해 발생하는 무한루프가 발생할 수 있는 이유와 똑같기 때문이다. 왜냐면 fetch 를 통해서 데이터를 받아온다면, 사실상 setState() 를 통해 state 를 변경해 주어야 하는데 그렇게 된다면 위에 적힌 것처럼 render 하는 부분에서 setState() 를 통해 state 가 변경되면서 다시 render 가 실행되는 무한반복루프가 발생하게 된다.


Sprint Review

setState() 를 통해 state 를 변화시켜야 하는 이유

life cycle 에 영향을 미치기 때문. 만약 setState() 가 아니라 직접 할당으로 변화시키면 life cycle 메서드가 가 호출되지 않는다.

"동적으로" 렌더링하기

이번 테스트 케이스의 일부는 어떤 고정된 데이터를 사용했을때만 작동하는 하드코딩을 방지하고, 재사용이 가능한 함수/모듈로서 만드는 데 의의가 있었다.

왜 공통 부모 컴포넌트를 가져야 하는가

그 이유는, React 의 데이터 흐름은 단방향이기 때문에 공통 부모로부터 주고받는 과정이 필요하기 때문이다.

babel, 그리고 webpack

babelJSX 가 담긴 코드를 .js 로 만들어주는 나름의 컴파일러이다. webpack 은 여러가지 파일들(HTML, CSS, JS, PNG, JS 등등...) 이 하나의 .js 파일로 컴파일시켜주는 기능이다.

그리고 저 babelwebpack 이 같이 있는 것이 들어가있게 create-react-app 이다.

redux 를 시작하기 전

두 개의 branch 가 있는데, 이 코드들이 이해가 가지 않는다면 redux 스프린트를 진행하지 말아라. 먼저 이해하고 진행하라는 이야기이다.


Redux

what is Redux?

Redux 는 상태, 즉 우리가 클래스 컴포넌트로만 사용할 수 있었던 그 상태를 관리하는 컴포넌트이다. 원래대로라면 상태관리를 위해 부모 컴포넌트 정도는 클래스 컴포넌트를 사용해야 했는데, Redux 를 사용하면 꼭 클래스 컴포넌트를 사용하지 않아도 상태관리를 할 수 있기 때문에 함수 컴포넌트만 사용해도 되어서 코드가 조금 더 간결해질 수 있다는 장점을 누릴 수 있다. 이번 스프린트의 목적은 컴포넌트와 상태를 분리하는 것 이다.

Intro to State Management

statesetState 통해서 관리해준다면?

공통의 부모가 되어주는 컴포넌트를 만든다. 그리고 그 컴포넌트는 상태를 받아서 자식 컴포넌트들과 소통을 해야 하기때문에 클래스 컴포넌트로 구성한다. 그리고 부모 컴포넌트는 컴포넌트 자신의 상태(state)를 변경할 수 있는(setState를 포함한) 메서드들을 자신에게 바인딩을 하고, 그리고 그것을 props 의 형태로 자식 컴포넌트들에게 내려준다. 자식 컴포넌트들은 자신의 데이터 등등을 해당 메서드를 통해 부모 컴포넌트로 올려보내서(lifting state up) 부모 컴포넌트의 상태를 바꾸어준다. 그렇게 바뀐 컴포넌트를 필요로 하는 또 다른 자식 컴포넌트들이 있다면 부모 컴포넌트는 그 자식 컴포넌트로 바뀐 state 를 내려보내준다.

추가로 가정 - 복잡한 구조의 다양한 컴포넌트들이 컴포넌트의 정보를 필요로 한다면?

React 만으로는 하나하나 다 부모-자식 관계로 엮어주어야 하는 그런 전통적인 방법밖엔 없다. 그러나 제목처럼 "복잡한 구조" 라는 가정이 붙어버린다면, 그 이야기의 무게는 달라진다.
이전의 스프린트에서는 그렇게 복잡하지 않았지만, 더 복잡한 구조를 생각해보자. 컴포넌트 안에 컴포넌트가 있고, 그 안에 또 다른 컴포넌트가, 또 그 안에 또 다른 컴포넌트가 있는, 마치 마트로슈카같이 nested 된 구조라면 신경써야 할 부분이 상당히 많아진다. 복잡하며, 복잡한 과정은 더 많은 오류를 야기한다.

대안 - 컴포넌트가 접근할 수 있는 공통적인 state 저장소(state store)가 있다면?

이런 공통적인 저장소가 있다면 위와 같은 복잡한 상황을 해결할 수 있다. 왜냐면, 그냥 컴포넌트 단에서 위에 적힌 state store 에 접근할 수 있게 만들어 버린다면 nested 된 구조여도 그 구조를 계속해서 파고들 필요가 없어지기 때문이다. 그냥 그 구조 속의 필요한 컴포넌트와 공통적인 상태 저장소끼리만 소통을 하면 되는 것이다.

그것이 바로 오늘 공부할 Redux 의 핵심 개념이다.

Redux Sprint Intro

Redux 란 무엇인가?

Redux is a predictable state container for JavaScript apps.
It helps you write applications that behave consistently, run in different environments (client, server, and native), and are easy to test. On top of that, it provides a great developer experience, such as live code editing combined with a time traveling debugger.
You can use Redux together with React, or with any other view library. It is tiny (2kB, including dependencies), but has a large ecosystem of addons available.

출처 : Redux 홈페이지의 소개

Redux 는 JS 에서 사용 가능한 state container 이다.

왜 Redux 를 사용해야 하는가?

React 로 개발을 할 때, 우리는 state 를 사용하기 위해서는 클래스 컴포넌트만을 사용해야 했다. 그리고 그 state 는 컴포넌트 "안에서만" 접근할 수 있었다. (우회적으로 컴포넌트를 통해서 접근하는 방법들도 컴포넌트 안에서 결국 state 에 접근하는 과정을 거쳐야 하므로)

class Clock extends React.Component {
	constructor(props) {
		super(props)
		this.state = { date: new Date(); }
	}

	render() {
		return(
			<div>It is {this.state.date.toLocaleTimeString()}</div>
		);
	}

}

그리고 그 컴포넌트(컴포넌트 안에 있는 컴포넌트)간의 state 를 공유하기 위해서는 컴포넌트들이 공통으로 가지고 있는 부모 컴포넌트의 state 를 통해서 연결해 주어야 했다. 그러나, 위에서 말 했듯 해당 방법은 같은 depth 에 있지만 breadth 값이 큰 컴포넌트간의 state 공유를 할 때 파이프라인을 일일히 뚫어주어야 한다는 단점이 있다.

Redux 는 이를 더욱 간편하게 만들어주기 때문에 사용한다.

Redux 의 기본적인 개념 - 세 가지 원칙

  • single source of truth

store 라는, 상태가 관리되는 단 하나의 공간이 상태들의 중점이 됨.

  • state is read-only

action, the pure javascript object. 상태를 순수한 action 이라는 JS 객체에 기록하여 store 에 보냄.

  • changes are made with pure functions

we use pure function, reducer, 현재 상태와 변화가 일어나서 받은 변경된 상태(action) 를 합쳐 다음 상태를 만들어냄. 특히, "순수함수" 라는 단어가 중요하다.

Redux 를 통한 state handling 의 도식화

핵심 개념은 reducer 라는 순수함수를 이용해 기존의 stateaction 을 통해 새로 주입된 state 를 합쳐(blend) 새로운 state 를 만들어 낸 뒤 다시 store 에 저장 후, 해당 state 를 참조하는 component 들이 업데이트를 하는 방식이다.

Redux 의 장점

  • 상태가 예측 가능하다

상태변화가 어떤 식으로 돌아가는지를 알고, pure function 을 이용한 상태변화를 일으키기 때문에 같은 인풋을 넣으면 같은 아웃풋을 return 받는단 체계를 보장한다. 그렇기 때문에 예측이 가능하다.

  • 유지보수에 용이하다

기존의 React 를 개발하는 방식처럼 props 를 일일히 뚫어서 내려주지 않아도 된다. 그렇기에 유지보수를 하면 신경써야 할 것들이 줄어들고, 그로 인해 유지보수가 상대적으로 더욱 용이해진다.

  • 디버깅에 유리하다

그러나 이는 aciton 과 state 로그를 기록한다는 가정 하에 유리하다.

  • 테스트를 붙이기 쉽다

순수함수를 기반으로 한 reducer 를 사용하기 때문에 테스트를 붙이기가 쉽다.


오늘은 redux 를 스스로 공부하는 과정의 내용과 redux 를 스스로 공부하기 전(소개나, 기존에 했던 스프린트에 대한 기록들 등등)의 내용을 분리해야 할 것 같아서 1편과 2편으로 분리합니다.

profile
правда и красота, truth and beauty

0개의 댓글