최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday

티스토리 뷰

FLUX pattern

Flux 패턴

자바스크립트에서 데이터 레이어를 생성하기위한 아키텍쳐로 Flux라는 이름으로 패턴이 구현되었다.

프로그램의 데이터에 대한 명확하고 이해하기 쉬운 업데이트 경로를 만드는데 중점을 둔다.

개발과정에서는 변경사항을 추적하는 것이 간단하고, 버그를 찾고 수정하는것이 용이해진다.

개요

플럭스를 가장 잘 설명하기 위해 MVC와 같은 주요 클라이언트 측 아키텍처 중 하나와 비교해 보면 알 수 있는데, 클라이언트 측 MVC 애플리케이션에서 사용자의 상호 작용은 컨트롤러의 코드를 트리거한다. 컨트롤러는 모델의 메소드를 호출하여 하나 이상의 모델에 대한 변경 사항을 조정하는 역할을 한다. 이는 모델이 변경되면 하나 이상의 뷰에 통보하고 모델에서 새 데이터를 읽고 사용자가 새 데이터를 볼 수 있도록 업데이트한다.

https://t1.daumcdn.net/cfile/tistory/990BAF3B5C8714D413

MVC는 어플리케이션의 규모가 커지면서 controller, model, view가 추가되는데

종속성이 더욱 복잡해진다.

https://t1.daumcdn.net/cfile/tistory/997E1E3B5C8714D30F

단 3 개의 뷰, 하나의 컨트롤러 및 하나의 모델을 추가했을뿐인데

종속성 관계는 이미 추적하기가 더 어려워졌다.

사용자가 UI와 상호 작용할 때 여러 가지로 분기된 경로로 코드가 실행되고

응용 프로그램에서는 디버깅 할때에도 문제가 되는데

특히나 런타임에서 구동되는 프로그램의 경우 실행되면서 발견할 수 있는 잠재적 버그를 찾는것 또한 이러한 경로 중 하나 (또는 그 이상)의 어떤 모듈에 버그가 있는지 파악하는 데 많은 불편함이 있다.

최악의 경우, 사용자 상호 작용은 업데이트를 트리거하고 추가 업데이트를 트리거하므로 오류가 발생하기 쉽고 디버깅하기 어려울 수 있다.

이 중 일부는 중복되는 경로를 따라 계단식 효과가 발생하기도 한다.

Flux는 단방향 데이터 흐름을 선호하여이 디자인을 피한다.

뷰 내의 모든 사용자 상호 작용은 작업 생성자를 호출하여 싱글 톤 전달자에서

작업 이벤트를 발생시킨다 .

디스패처는 플럭스 적용시 모든 동작에 대해 단일 포인트 송출만을 갖는다.

액션은 디스패처에서 전송되고 store작업에 대한 응답으로 업데이트 한다.

https://t1.daumcdn.net/cfile/tistory/99B9733B5C8714D316

간단한 플럭스 흐름

추가된 store 또는 뷰에 대한 플로우는 크게 변경되지 않습니다.

Dispatcher는 모든 작업을 응용 프로그램의 모든 store에 보낸다.

저장소를 실제로 업데이트하는 방법에 대한 내용은 store에 포함되어있지 않다.

store 자체는 이벤트가 Dispatcher된 비즈니스 로직만을 갖고있다.

각 저장소는 응용 프로그램의 작업에 대한 응답으로만 업데이트된다.

https://t1.daumcdn.net/cfile/tistory/99CEC83B5C8714D315

복잡한 플럭스

보다 복잡한 플럭스 흐름

저장소가 업데이트되면 변경 이벤트가 발생한다.

많은 React 어플리케이션에서 특별한 뷰 ( "컨트롤러 뷰"라고도 함)는 이 변경 이벤트를 감시하고, 저장소의 새 데이터를 읽고, 해당 데이터를 속성을 통해 하위 뷰에 전달되게 된다.

저장소 변경 이벤트에 대한 React 응용 프로그램에서 최상위에서 다시 렌더링을 트리거하고 효과적으로 (React가 효율적인 방식으로 처리하는) 나타내기때문에, 모든 계층 구조를 다시 렌더링하는 경우는 드물게된다. 이는 모델의 특정 속성 변경을 감시하고 일부보기만 수정하려고 시도 할 때 발생할 수있는 복잡한 버그 및 성능 문제를 완전히 방지할 수 있다.

바닐라 자바스크립트에 flux 패턴을 적용하여 구현한 예제

 

 

const elNumber = document.getElementById('number');
const btnIncrement = document.getElementById('increment');
const btnDecrement = document.getElementById('decrement');
const description = document.getElementById("description");
 
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';
 
const increment = (diff) => ({ type: INCREMENT, diff });
const decrement = () => ({ type: DECREMENT });
 
// 초기값
const initialState = {
  number: 0,
  description: "대기중"
};
 
// reducer
const reducer = (state = initialState, action) => {
  console.log(action);
  switch(action.type) {
    case INCREMENT:
      return { 
        number: state.number + action.diff,
        description: "증가"
      };
    case DECREMENT:
      return { 
        number: state.number - 1,
        description: "감소"
      };
    default:
      return state;
  }
}
 
// store: 리덕스의 스토어 생성하여, 리듀서를 넣고 만듬
const { createStore } = Redux;
const store = createStore(reducer);
 
const render = () => {
  elNumber.innerText = store.getState().number;
  description.innerText = store.getState().description;
}
 
// 스토어구독: 렌더
store.subscribe(render);
 
render();
 
// 버튼 이벤트
btnIncrement.addEventListener('click', () => {
  store.dispatch(increment(25));
})
 
btnDecrement.addEventListener('click', () => {
  store.dispatch(decrement());
})

 

 

'■ 프론트엔드 ■ > JavaScript' 카테고리의 다른 글

마우스에 반응하는 css3 perspective  (1) 2023.12.08
await-to-js  (0) 2022.12.05
eval 대신에 Function  (0) 2022.08.19
typescript - .tsconfig.json  (0) 2022.01.12
단어강조  (0) 2021.05.03
댓글