main docs

 

심화 문서

 

React component

  • props를 전달 받아 React Element를 반환하는 function 혹은 class
  • state라는 내부 상태를 가질 수 있음
  • props는 react component의 파라미터, state는 react component의 필드라고 생각하면 됨.
  • 함수 컴포넌트는 클래스가 아니라 필드를 가질 수 없으니 `` useState`` 구문을 사용함 (사실 본질적으로 hook을 사용하는 이유는 main docs를 참조)

 

React state 관리

  • https://ko.reactjs.org/docs/react-component.html
  • ``js this.state``를 직접 변경하면 안 됩니다. 왜냐하면 이후 호출되는 ``js setState()``가 이전에 적용된 변경 사항을 덮어쓰기 때문입니다. ``js this.state``를 불변적(Immutable)인 데이터로 취급하세요.
  • 애초에 함수형 컴포넌트를 사용하는 것이 낫지만, 이미 클래스 컴포넌트로 작성 되어 있는 경우.

```js

// 리스트에 추가 삭제

e.currentTarget.checked === true
  ? this.setState(state => ({checkedItems: [...state.checkedItems, divisionRateItem]}))
  : this.setState(state => ({checkedItems: state.checkedItems.filter(x => x !== divisionRateItem)}));

 

// 리스트 안의 원소의 멤버 변수 변경

this.setState(prevState => {
  const state = Object.assign({}, prevState);
  state.divisionRates[i].isChecked = !state.divisionRates[i].isChecked;
  return state;
});

 

// 이건 별로 좋은 방법은 아닌 것 같다. 전체를 리턴 받아야 해서 filter를 못쓰고 map에 다 때려 넣었는데

// 너무 지저분해지고 가독성도 좋지 않다

this.setState(state => ({divisionRates:
        state.divisionRates
            .map(divisionRate =>
                divisionRate === selectedItem 
                    ? {...divisionRate, isChecked: !divisionRate.isChecked} 
                    : divisionRate)}));

 

this.setState(state => ({
    divisionRates: state.divisionRates
        .map(item => Object.assign(item, {isChecked: !!checked}))
}));

```

MobX를 사용하는 경우 setState를 안써도 된다. observer가 자동으로 추적하기 때문.

 

React Context

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

 

  • React에서 데이터는 props를 통해 위에서 아래로(parent에서 child로) 전달된다.
    • props는 react component의 파라미터라고 생각하면 됨.
  • 그러나 이렇게 top-down 방식으로 데이터를 전파하는 것은 앱이 약간만 규모가 커져도 전달해야 하는 props가 많아진다. 쓸데없는 props를 단지 전달 목적으로 받는 경우도 있을거고... 전달... 전달... 전달... 이다.
  • 그래서 context라는 개념이 도입되었고, context를 이용하면 컴포넌트 트리 전체에 데이터를 제공할 수 있다.
    • 예를들면 로케일, UI 테마 등. 앱 안의 여러 컴포넌트에게 전달해줘야 하는 데이터인 경우.

 

MobX

 

MobX와 React Context를 모두 사용하여 [store -> context(provider), useHoC -> container] 구조로 사용 중

 

 

---

 

MobX가 왜 필요한가?

  • MobX는 React에 종속적이지 않은 독립적으로 사용 가능한 라이브러리다. (하지만 대체로 React와 함께 사용한다.)
  • observer가 observable 지정된 state를 감시하다가, state에 변화가 생기면 re-render한다.
    • vanilla React는 setState를 사용해야 하지만, MobX에서는 이를 사용하지 않는다. 알아서 observer가 observable을 관찰하고 re-render 한다.
    • observable은 도메인 객체, observer는 이를 감시하는 액터라고 생각하면 된다.
    • each component individually re-renders when relevant data changes.
  • MobX를 사용할 때, observer가 안붙으면, 해당 react component에서 참조하고 있는 변수(state)에 변화가 생겨도 re-render가 일어나지 않는다. (re-render만 안될 뿐 함수 호출이라던지 나머지는 동작함)

 

헌데 생각해보면 React만 사용해도 state가 변경되면 그를 참조하고 있는 컴포넌트(view)가 re-render 된다.

단지 observable의 re-render만 필요한 거 였다면 그냥 리액트 써도 될텐데, 왜 MobX가 필요한 것일까?

 

MobX나 Redux는 "state 관리 라이브러리" 다.

상태 관리 라이브러리란, 말 그대로 state를 쉽게 관리하도록 지원하는 라이브러리다.

  1. 특히 React만으로는 처리하기 어려웠던 글로벌 상태 관리(context)를 지원
  2. 상태 업데이트 로직 분리 가능
  3. 더 손쉬운 상태 관리 (라이브러리 코드 스타일. 개발 방식) - setState 걷어내기
  4. 성능 : state 변경 시 발생하는 re-render 최적화
  5. 미들웨어 등 (Redux의 경우)

 

(1) 이전에는 글로벌 상태 관리 하나만으로도 가치가 있었는데, React가 Context API를 지원하기 시작하면서 React 만으로도 글로벌 상태 관리가 가능해졌다.

그래서 단순히 글로벌 상태만 사용하려는 목적이라면 Context API만으로도 커버가 되나, 상태 관리 라이브러리가 글로벌 상태 관리만 제공하는 것은 아니다.

 

(2) useReducer로도 가능하다. 하지만 코드 스타일이 마음에 안들 수 있음.

 

(4) yobi [공유] 스마트에디터 React, MobX 개선 사례벨로퍼트 - 리덕스 잘 쓰고 계시나요?

 

The observer HoC automatically subscribes React components to any observables that are used during rendering.
As a result, components will automatically re-render when relevant observables change. It also makes sure that components don't re-render when there are no relevant changes. So, observables that are accessible by the component, but not actually read, won't ever cause a re-render.
MobX reacts to any existing observable property that is read during the execution of a tracked function(observer).
https://ko.mobx.js.org/understanding-reactivity.html

 

이 밖에도 setState로 인한 다양한 문제점이라던지.. MobX를 사용했을 때의 장점은 찾아보면 많이 나온다.

https://simsimjae.tistory.com/448

 

MobX 어떻게 사용해야 하나

observer와 observable은 항상 사용하면 되는건가?

You might be wondering, when do I apply observer? The rule of thumb is: apply observer to all components that read observable data.

Usually all your components should be wrapped by observer. Don't worry, this is not inefficient. On the contrary, more observer components make rendering more efficient as updates become more fine-grained.

 

observer 내에 observable이 어떤 출처로 왔는지, 어떻게 전달되었는지는 상관없다. 하지만 React Context를 사용해 전달하는 것을 추천

 

observer가 아닌 컴포넌트에 observable을 넘기지 마라

 

너무 빨리 필드를 풀어서 전달할 필요는 없다 (역참조는 최대한 늦게 해라)

```js

Slower : <DisplayName name={person.name} />

Faster : <DisplayName person={person} />

```

  • (중요) MobX는 observable 값이 변경 되었을 때, 해당 값을 참조(referencing)하고 있는 컴포넌트들을 모두 re-render 하기 때문임.
    • 매우 중요. 참조 하는 것 만으로도 re-render 대상이 되기 때문에 불필요한 re-render가 발생 할 수 있음. 
    • computed를 활용하자. 스마트에디터 개선 사례 참조
    • computed는 값을 캐싱하고 있다가 내부 값에 변경이 발생하면 body를 실행하며 캐시를 갱신함
  • person.name은 여기서 쓰이는 코드가 아닌데 풀어서 전달했다고 가정하자.
    • 그냥 person 넘겨도 상관 없는 상황. 즉 person.name이 변경되었을 때 현위치 컴포넌트는 re-render 될 필요가 없는 상황임.
  • 이 때 만약 person.name이 변경된다면 이를 참조하고 있는 현위치 컴포넌트까지 re-render 대상이 된다.
  • There is nothing wrong with that, and if rendering of the owning component is fast enough (usually it is!), then this approach works well.

 

리스트 렌더링에는 전용 컴포넌트를 사용하는 것이 좋다

  • 물론 리스트 컴포넌트 중에서, 변경이 있는 컴포넌트만 re-render되는 것은 맞다.
  • 하지만 re-rendering 되지 않도록 하면 끝인가? 아니다.
  • 조정(reconcile) 프로세스 자체가 비용이 많이 들기 때문. (상세한 내용과 Good practice)

 

기타

profile에 따라 다른 상수 불러오기

```js

// Common.js

export default {

    ...require(`../profiles/${process.env.REACT_APP_PROFILES}`)

}

```

```js

// local.js

export const a = 'constant'

```

빌드 시에 profile을 다음과 같이 넣어주면 해당 프로파일.js 파일의 상수들만 불러올 수 있다.

```js

cross-env REACT_APP_PROFILES=local react-scripts build

```

사용할 때는 Common을 import해서 사용.

 

react에서 POST body는 처리할수 없음.

 

react에서는 DOM element에 사용하는 키워드를 바꿔줘야 함

https://ko.reactjs.org/docs/dom-elements.html  

for -> htmlFor / class -> className 으로 변경되는 등.

 

사례

yobi [공유] 스마트에디터 React, MobX 개선 사례  

우아한형제들 React에서 Mobx 경험기 (Redux와 비교기)  

벨로퍼트 - 리덕스 잘 쓰고 계시나요?  

벨로퍼트 - 상태 관리 라이브러리 : Redux, MobX