반응형

박스의 width와 height를 어떻게 구하는지 정하는 방식

 

box-sizing = content-box | border-box | initial | inherit

 

값 

content-box 기본값. width와 height가 콘텐츠 영역만 포함하고 안팎 여백 & 테두리를 포함하지 않는다
border-box width와 height가 안팎 여백 & 테두리를 포함한다. 
initial 초기 값으로 지정 
inherit 부모로부터 상속

 

예제

 

border-box

content-box

 

 

<!DOCTYPE html>
<html>
<head>
<style> 
div.container {
  width: 100%;
  border: 2px solid black;
}

.content-box {
  box-sizing: content-box;
  width: 50%;
  border: 5px solid red;
  float: left;
}

.border-box {
  box-sizing: border-box;
  width: 50%;
  border: 5px solid red;
  float: left;
}


</style>
</head>
<body>

<div class="container">
  <div class="border-box">border-box</div>
  <br>
  
  <div class="content-box">content-box</div>
  <div style="clear:both;"></div>
</div>

</body>
</html>

 

가로 세로 길이의 정확한 값을 원하면 border-box 설정을 해두자 

 

reference 

 

https://www.w3schools.com/cssref/css3_pr_box-sizing.asp

반응형

'Front-end > CSS' 카테고리의 다른 글

font-family 상속 시키기  (0) 2022.11.04
css 챌린지  (0) 2022.10.05
[CSS] Gap  (0) 2022.06.13
loading spinner  (2) 2022.02.13
CSS 애니메이션 성능 개선  (0) 2022.01.27
반응형

props drilling을 줄이고 사용하는 입장에서 '조합'해서 사용할 수 있도록 하는 패턴 

 

예를 들어 

아래와 같은 코드가 있고, 내부적으로 2~4단계의 트리 depth단계로 구성된 컴포넌트가 있다면

<Counter text="example" ex1={<div></div>} onchange{()=>{ console.log(change)}} onClick={() => console.log('test1')}>

 

사용하는 입장에서는 내부 구성을 정확하게 알 수 없을것이다.

그래서 사용자 입장에서 컴포넌트를 직접 조합해서 구현하고 props를 직접 내려주는 방식이다.

 

코드 예시)

export default function AppEx() {
  return (
    <div>
      <Counter onClick={() => console.log('test1')}>
        <Counter.Increment />
        <Counter.Decrement />
        <Counter.Label />
      </Counter>

      <Counter onClick={() => console.log('test2')}>
        <Counter.Increment />
        <Counter.Label color="blue" />
        <Counter.Decrement />
      </Counter>

      <Counter onClick={() => console.log('test3')}>
        <Counter.Increment />
        <Counter.Label color="red" />
      </Counter>
    </div>
  );
}

 

구현된 화면 예시

 

장점 

 

매우 높은 유연성

선언적으로 구성 -> 가독성이 좋음 

하나의 giant component를 쪼개 여러개로 분리함으로써 복잡성이 줄어듬 

 

단점

 

매우 높은 유연성(실수 혹은 의도치 않는 코드 삽입 가능성 증가)

코드가 좀 복잡해짐

JSX 크기 증가

 

코드 예시)

import React, { useEffect, useState, Children } from 'react';
import styled from 'styled-components';

import { Decrement, Increment, Label, Reset } from './modules';

const StyledDiv = styled.div`
  display: inline-flex;
  flex-direction: row;
  border: 0.5px solid;
  gap: 0.5px;

  margin: 30px;
`;

function Counter({ children, onClick }) {
  const [counter, setCounter] = useState(0);
  const resetCounter = () => setCounter(0);

  return (
    <StyledDiv onClick={onClick}>
      {Children.map(children, (child) => {
        return React.cloneElement(child, {
          counter,
          resetCounter, // 그냥 첨가 가능하다는 예시용
          setCounter,
        });
      })}
    </StyledDiv>
  );
}

Counter.Reset = Reset;
Counter.Increment = Increment;
Counter.Decrement = Decrement;
Counter.Label = Label;

export default function AppEx() {
  return (
    <div>
      <Counter onClick={() => console.log('test1')}>
        <Counter.Increment />
        <Counter.Decrement />
        <Counter.Label />
      </Counter>

      <Counter onClick={() => console.log('test2')}>
        <Counter.Increment />
        <Counter.Label color="blue" />
        <Counter.Decrement />
      </Counter>

      <Counter onClick={() => console.log('test3')}>
        <Counter.Increment />
        <Counter.Label color="red" />
      </Counter>
    </div>
  );
}

 

구현하는 방식은 Context Api를 사용하는 방식과 Children와 cloneElement를 사용하는 방식 2가지를 발견했는데

 

ex) children & cloneElement 이용

function Counter({ children, onClick }) {
  const [counter, setCounter] = useState(0);
  const resetCounter = () => setCounter(0);

  return (
    <StyledDiv onClick={onClick}>
      {Children.map(children, (child) => {
        return React.cloneElement(child, {
          counter,
          resetCounter, // 그냥 첨가 가능하다는 예시용
          setCounter,
        });
      })}
    </StyledDiv>
  );
}

ex) context api 이용

const CounterContext = createContext(undefined);

function CounterProvider({ children, value }: any) {
  return <CounterContext.Provider value={value}>{children}</CounterContext.Provider>;
}

function useCounterContext() {
  const context = useContext(CounterContext);
  if (context === undefined) {
    throw new Error('useCounterContext must be used within a CounterProvider');
  }
  return context;
}

function Counter2({ children, onClick }) {
  const [counter, setCounter] = useState(0);
  const resetCounter = () => setCounter(0);

  const handleIncrement = () => {
    setCounter(counter + 1);
  };

  const handleDecrement = () => {
    setCounter(counter - 1);
  };

  return (
    <CounterProvider value={{ counter, handleIncrement, handleDecrement }}>
      <StyledDiv onClick={onClick}>{children}</StyledDiv>
    </CounterProvider>
  );
}

children & cloneElement 방식의 경우 cloneElement라길래 복사하는 비용이 크지 않을까? 검색해봤는데 

 

stackoverflow에 따르면 

어차피 JSX가 React.createElement(Object)로 전환되는 과정에서 cloneElement를 쓰면 똑같이 Object로 전환되면서 props만 전달해서 바꿔주는 식으로 작동해서 성능 이슈는 큰 문제가 아니라고 한다.

 

https://stackoverflow.com/questions/54922160/react-cloneelement-in-list-performance

 

React.cloneElement in List performance

I have doubts about React.cloneElement in List. Is that something that we should avoid doing or not, if we have lots of elements in list? Does React.cloneElement makes unnecessary re-renders that c...

stackoverflow.com

 

cloneElement 방식의 경우 depth가 깊어지면 다루기 좀 힘들어질꺼 같지만 간편하고

Context API 방식은 boilerplate?를 까는게 번거롭긴 하지만 depth에 상관없이 사용 가능할꺼 같다.

 

headlessui 란 오픈소스는 context 방식을 사용한것으로 보인다.

 

그외 비슷한 패턴들

 

쓸만한게 있을까 빠르게 훑고 넘어가자

 

Control Props Pattern

 

import React, { useState } from "react";
import { Counter } from "./Counter";

function Usage() {
  const [count, setCount] = useState(0);

  const handleChangeCounter = (newCount) => {
    setCount(newCount);
  };
  return (
    <Counter value={count} onChange={handleChangeCounter}>
      <Counter.Decrement icon={"minus"} />
      <Counter.Label>Counter</Counter.Label>
      <Counter.Count max={10} />
      <Counter.Increment icon={"plus"} />
    </Counter>
  );
}

export { Usage };

Example

 

Github: https://github.com/alexis-regnaud/advanced-react-patterns/tree/main/src/patterns/control-props

 

컴포넌트를 제어 컴포넌트로 사용 

하나의 'single source of truth' 단일 상태 사용 -> base component에 custom logic과 상태 부여

 

장점 

직접적 제어권 부여

 

단점

(compound 패턴보다) 구현의 복잡성 -> state, function, component 제어가 필요

 

 

Custom Hook Pattern

import React from "react";
import { Counter } from "./Counter";
import { useCounter } from "./useCounter";

function Usage() {
  const { count, handleIncrement, handleDecrement } = useCounter(0);
  const MAX_COUNT = 10;

  const handleClickIncrement = () => {
    //Put your custom logic
    if (count < MAX_COUNT) {
      handleIncrement();
    }
  };

  return (
    <>
      <Counter value={count}>
        <Counter.Decrement
          icon={"minus"}
          onClick={handleDecrement}
          disabled={count === 0}
        />
        <Counter.Label>Counter</Counter.Label>
        <Counter.Count />
        <Counter.Increment
          icon={"plus"}
          onClick={handleClickIncrement}
          disabled={count === MAX_COUNT}
        />
      </Counter>
      <button onClick={handleClickIncrement} disabled={count === MAX_COUNT}>
        Custom increment btn 1
      </button>
    </>
  );
}

export { Usage }

Example

Github: https://github.com/alexis-regnaud/advanced-react-patterns/tree/main/src/patterns/custom-hooks

 

장점
제어의 역전 -> 메인 로직이 custom hook으로 전환

 

단점

 

로직과 렌더링UI의 분리 -> (남이 보기에) 가독성 하락

 

 

Props Getters Pattern

 

import React from "react";
import { Counter } from "./Counter";
import { useCounter } from "./useCounter";

const MAX_COUNT = 10;

function Usage() {
  const {
    count,
    getCounterProps,
    getIncrementProps,
    getDecrementProps
  } = useCounter({
    initial: 0,
    max: MAX_COUNT
  });

  const handleBtn1Clicked = () => {
    console.log("btn 1 clicked");
  };

  return (
    <>
      <Counter {...getCounterProps()}>
        <Counter.Decrement icon={"minus"} {...getDecrementProps()} />
        <Counter.Label>Counter</Counter.Label>
        <Counter.Count />
        <Counter.Increment icon={"plus"} {...getIncrementProps()} />
      </Counter>
      <button {...getIncrementProps({ onClick: handleBtn1Clicked })}>
        Custom increment btn 1
      </button>
      <button {...getIncrementProps({ disabled: count > MAX_COUNT - 2 })}>
        Custom increment btn 2
      </button>
    </>
  );
}

export { Usage };

 

장점

 

getter를 통한 쉬운 사용 및 통합

복잡성을 getter에 감춤으로써 복잡성을 숨김

 

단점

 

Lack of visibility ->  getter가 어떻게 구현되어 있는지 모르는 사람들에게는 가독성이 하락한다

  //props getter for 'Counter'
  const getCounterProps = ({ ...otherProps } = {}) => ({
    value: count,
    "aria-valuemax": max,
    "aria-valuemin": 0,
    "aria-valuenow": count,
    ...otherProps
  });

getter는 이런식으로 구성되어있는데 spread 연산자로 뿌려주는 식이다.

 

State reducer pattern

 

custom hook 패턴에 reducer를 조합한 형태 

import React from "react";
import { Counter } from "./Counter";
import { useCounter } from "./useCounter";

const MAX_COUNT = 10;
function Usage() {
  const reducer = (state, action) => {
    switch (action.type) {
      case "decrement":
        return {
          count: Math.max(0, state.count - 2) //The decrement delta was changed for 2 (Default is 1)
        };
      default:
        return useCounter.reducer(state, action);
    }
  };

  const { count, handleDecrement, handleIncrement } = useCounter(
    { initial: 0, max: 10 },
    reducer
  );

  return (
    <>
      <Counter value={count}>
        <Counter.Decrement icon={"minus"} onClick={handleDecrement} />
        <Counter.Label>Counter</Counter.Label>
        <Counter.Count />
        <Counter.Increment icon={"plus"} onClick={handleIncrement} />
      </Counter>
      <button onClick={handleIncrement} disabled={count === MAX_COUNT}>
        Custom increment btn 1
      </button>
    </>
  );
}

export { Usage };

Example

Github: https://github.com/alexis-regnaud/advanced-react-patterns/tree/main/src/patterns/state-reducer

 

가장 파워풀하고 가장 Lack of visibility한 패턴이지 싶다.

 

느낀점?

 

협업시 가독성 문제 때문에 느낌상 1 ~ 3번 패턴이 젤 무난하지 않을까 싶다.

그 외로는 공통으로 사용할 수 있는 로직을 가지고(추상화) UI만 갈아끼우는 식으로 사용 가능할꺼 같다

 

reference 

 

https://javascript.plainenglish.io/5-advanced-react-patterns-a6b7624267a6

 

5 Advanced React Patterns

An overview of 5 modern advanced React patterns, including integration codes, pros and cons, and concrete usage within public libraries.

javascript.plainenglish.io

 

반응형

'소프트웨어공학 > 디자인패턴' 카테고리의 다른 글

메모  (0) 2022.03.25
프론트엔드에서의 레포지토리 패턴?  (0) 2022.03.18
[행위] 책임 연쇄 패턴  (0) 2022.03.13
[행위] 전략 패턴 & 커맨드 패턴  (0) 2022.03.07
[행동] 중재자 패턴  (1) 2022.03.01
반응형

Gap

'내부의 children 요소'들이 일정한 간격으로 떨어져 위치할 수 있게 사용하는 요소

grid 혹은 flex에서 사용 가능하다.

 

margin과의 차이점 

 

-> gap 스타일 속성은 인접한 요소가 있을때만 Gap을 만든다

 

See the Pen Untitled by lodado (@lodado) on CodePen.

 

호환성

 

출처 : https://caniuse.com/?search=GAP

메이저 브라우저는 전부 지원하는거 같은데 앞으로 호환성이 더 좋아지면 편리하게 쓸 수 있을것으로 기대된다.

 

ref

 

https://webisfree.com/2020-12-05/[css]-%EC%8A%A4%ED%83%80%EC%9D%BC%EC%86%8D%EC%84%B1-gap%EC%9D%84-flex%EC%97%90%EC%84%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0 

 

[css] 스타일속성 gap을 flex에서 사용하기

CSS 스타일 속성 gap에 대하여 알아보려고 합니다.

webisfree.com

반응형

'Front-end > CSS' 카테고리의 다른 글

font-family 상속 시키기  (0) 2022.11.04
css 챌린지  (0) 2022.10.05
[CSS] box-sizing  (0) 2022.07.11
loading spinner  (2) 2022.02.13
CSS 애니메이션 성능 개선  (0) 2022.01.27
반응형

react 17은 큰 변화는 없고 점진적인 upgrade를 위한 단계라고 한다.

 

 

이벤트 위임의 변경점

 

기존에는 document에 이벤트 위임을 붙여 이벤트를 처리했다면

17부터는 root에 이벤트를 붙여서 처리

 

https://ko.reactjs.org/blog/2020/08/10/react-v17-rc.html#changes-to-event-delegation

ex) 

<button onClick={handleClick}>

 

 

위 코드같은경우엔 내부적으로 

 

const rootNode = document.getElementById('root');
ReactDOM.render(<App />, rootNode);

 

root에 이벤트 위임을 넣어 처리

기존에는 (예시로) 리엑트 내부 e.stopPropagation() 코드가 혼용되서 쓰여지고 있는 JQuery 이벤트를 prevent하는 일이 있었는데

이런일을 방지하게 변경

또한 React17에서 event propagation이 보다 regular dom에 가깝게 변경

 

 

브라우저 최적화 (잡다한 변경점)

 

1. onScroll이 네이티브에선 버블링되지 않는데 React onScroll은 버블링되서 이벤트 버블링 제거 

 

2.

onFocus = focusin

onBlur = focusout 이벤트 사용하도록 변경?

(focusin focusout은 버블링 발생) 

 

3. Capture phase events (e.g. onClickCapture) 가 이제 진짜 캡처 페이즈 리스너 사용 (이전엔 어케했누?)

 

이벤트 풀링 최적화 제거 (No Event Pooling)

 

“event pooling” optimization이 별 의미없어서 삭제

비동기적으로 이벤트 객체에 접근 불가능했던게 삭제됨

 

function handleChange(e) {
  setData(data => ({
    ...data,
    // This crashes in React 16 and earlier:
    text: e.target.value <- before v17 : null
  }));
}

 

난 2021 입문자라(react 17 이후 사용) event pooling이 무슨 역할이었는지 정확히는 모르겠다

SyntheticEvent 객체는 이벤트 핸들러가 호출된 후 초기화되기에, 비동기적으로 이벤트 객체에 접근할 수 없었던 것이 수정되었다고 한다.

 

아마 setData 실행시기와 e의 생명주기가 일치하지 않았던것(초기화되버려서)으로 추론된다.

 

Effect Cleanup Timing

useEffect(() => {
  // This is the effect itself.
  return () => {    // This is its cleanup.  };});

 

useEffect가 보다 효율적으로 변경 

 

기본 컨셉 : 

 

Most effects don’t need to delay screen updates, so React runs them asynchronously soon after the update has been reflected on the screen.

 

(For the rare cases where you need an effect to block paint, e.g. to measure and position a tooltip, prefer useLayoutEffect.)

 

그러나 보통은 unmounting 될때 cleanup function은 보통 동기적으로 실행되게 사용되어 왔다.

(similar to componentWillUnmount being synchronous in classes)

이것은 탭 변경과 같은 큰 페이지 변경시 속도 저하를 초래했다. 

 

그래서 React 17에서는 항상 cleanup function은 비동기적으로 실행되게 변경되었다.

 

(In React 17, the effect cleanup function always runs asynchronously — for example, if the component is unmounting, the cleanup runs after the screen has been updated.)

 

동기적 상황을 원하면 useLayoutEffect를 쓰시라

 

(you might want to rely on the synchronous execution, you can switch to useLayoutEffect instead)

 

추가적으로 cleanup function은 언제나 new Effect가 실행하기 전에 실행된다. 

useEffect(() => {
  const instance = someRef.current;
  instance.someSetupMethod();
  return () => {
    instance.someCleanupMethod();
  };
});

 

Consistent Errors for Returning Undefined

let Button = forwardRef(() => {
  // We forgot to write return, so this component returns undefined.
  // React 17 surfaces this as an error instead of ignoring it.
  <button />;
});

let Button = memo(() => {
  // We forgot to write return, so this component returns undefined.
  // React 17 surfaces this as an error instead of ignoring it.
  <button />;
});

return undefined하면 에러

(제대로 return 안하면 에러) 

 

만약 아무것도 return 하지 않는 것을 명시적으로 나타내고 싶다면 return null 사용

 

ref

https://han7096.medium.com/react-v17-release-candidate-톺아보기-6a4b091965c4

 

React v17 Release Candidate 톺아보기

변경사항과 유의할점을 React 공식 문서와, 개인적인 지식을 덧붙여 정리한 글

han7096.medium.com

https://reactjs.org/blog/2020/08/10/react-v17-rc.html

 

React v17.0 Release Candidate: No New Features – React Blog

Today, we are publishing the first Release Candidate for React 17. It has been two and a half years since the previous major release of React, which is a long time even by our standards! In this blog post, we will describe the role of this major release, w

reactjs.org

 

반응형

'Front-end > React' 카테고리의 다른 글

react-flow에 undo, redo 구현  (0) 2022.09.03
Suspense를 위한 wrapper 만들기  (0) 2022.07.28
React18(개인 공부 메모용)  (0) 2022.06.09
react TMI  (0) 2022.04.13
drag and drop으로 창 크기 조절  (0) 2022.03.18
반응형

notion link

https://silver-blue-23c.notion.site/React18-0d46d803f3be437dbe7f90348dbecd09

 

React18

React 18의 알파 버전이 출시

* 바로 막 쓰기엔 무리일듯

자동 배치(Automatic Batching)가 도입되어 배치가 개선

 

배치 : React가 더 나은 성능을 위해 여러 개의 state 업데이트를 하나의 리렌더링 (re-render)로 묶는 것을 의미)

React 18의 createRoot를 통해, 모든 업데이트들은 어디서 왔는가와 무관하게 자동으로 배칭되게 된다.

 

이 뜻은, 추가적으로 timeout, promise, native 이벤트 핸들러와 모든 여타 이벤트는 React에서 제공하는 이벤트와 동일하게 state 업데이트를 배칭할 수 있다. 이를 통해 우리는 렌더링을 최소화하고, 나아가 애플리케이션에서 더 나은 성능을 기대한다.

상태 업데이트에 배치가 적용되지 않았으면 하는 경우엔 새롭게 추가된ReactDOM.flushSync함수를 사용

 

useTransition

React 17 까지는 상태 업데이트를 긴급 혹은 전환으로 명시하는 방법 X

 

 모든 상태 업데이트는 긴급 업데이트 → setTimeout이나 throttle, debounce 등의 테크닉을 써서 긴급 업데이트 방해를 우회하는 것이 최선이였다

 

useTransition을 쓰면

일부 상태 업데이트를 긴급하지 않은 것 (not urgent)로 표시

이것으로 표시되지 않은 상태 업데이트는 긴급한 것으로 간주

긴급한 상태 업데이트 (input text 등)가 긴급하지 않은 상태 업데이트 (검색 결과 목록 렌더링)을 중단할 수 있다.

 

쓰는 이유 : 느린 렌더링 & 느린 네트워크

업데이트를 긴급한 것과 긴급하지 않은 것으로 나누어 개발자에게 렌더링 성능을 튜닝하는데 많은 자유를 주었다고 볼 수 있다.

 

useId

 

useId는 클라이언트와 서버간의 hydration의 mismatch를 피하면서 유니크 아이디를 생성할 수 있는 새로운 훅이다. 이는 주로 고유한 id가 필요한 접근성 API와 사용되는 컴포넌트에 유용할 것으로 기대

 

useDeferredValue

 

useDeferredValue를 사용하면, 트리에서 급하지 않은 부분의 재렌더링을 지연

지연된 렌더링을 인터럽트하고 사용자 입력을 차단할때 사용

이는 debounce와 비슷하지만, 몇가지 더 장점이 있다.

지연된 렌더링은 인터럽트가 가능하며, 사용자 입력을 차단하지 않는다.

 

***** 아래는 Library author들에게 권장하는 hook들*****

(아직 어디에 쓰는진 잘..? library 제작자한테 추천한다고 한다 특히 useSyncExternalStore)

 

useSyncExternalStore

 

스토어에 대한 업데이트를 강제로 동기화 하여 외부 스토어가 concurrent read를 지원할 수 있도록 하는 새로운 훅

**useEffect**가 필요하지 않고, 이는 리액트 외부 상태와 통합되는 모든 라이브러리에 권장된다.

 

 

용어 설명 :

  • External Store: 외부 스토어라는 것은 우리가 subscribe하는 무언가를 의미한다. 예를 들어 리덕스 스토어, 글로벌 변수, dom 상태 등이 될 수 있다.
  • Internal Storeprops context useState useReducer 등 리액트가 관리하는 상태를 의미한다.
  • Tearing: 시각적인 비일치를 의미한다. 예를 들어, 하나의 상태에 대해 UI가 여러 상태로 보여지고 있는, (= 각 컴포넌트 별로 업데이트 속도가 달라서 발생하는) UI가 찢어진 상태를 의미한다.

**useExternalStore**는 리액트 18에서 스토어 내 데이터를 올바르게 가져올 수 있도록 도와준다.

 

useInsertionEffect

 

css-in-js 라이브러리가 렌더링 도중에 스타일을 삽입할 때 성능 문제를 해결할 수 있는 새로운 훅

 

The signature is identical to useEffect, but it fires synchronously before all DOM mutations.

 

리액트가 DOM을 변환한경우, 레이아웃에서 무언가를 읽기전 (**clientWidth**와 같이) 또는 페인트를 위해 브라우저에 값을 전달하기 전에 DOM에 대한 다른 변경과 동일한 타이밍에 작업을 하면 된다.

 

→ We must ensure to manipulate the CSS rules at the same time as other changes to the DOM. It can be when React mutates the DOM, before anything is read from the layout and before the content is visible in the browser.

useLayoutEffect 과 비슷,

hook is used to read the layout from the DOM and synchronously re-render.

 

순서 UseInsertionEffect → useLayoutEffect → useEffect

 

this hook does not have access to refs and cannot schedule updates.

 

선택적(Selective) Hydartion 등의 동시성(Concurrent) 기능이 추가

 

이 파트는 알아두면 좋을듯

 

 

새로운 서버 사이드 렌더링 아키텍처가 도입(<Suspense>와 React.lazy를 지원)

및 부분 SSR 지원

React 18에는 렌더링을 위한 3가지 API가 존재

  • renderToString: 유지 (제한된 Suspense 지원)
  • renderToNodeStream: Deprecated (Full Suspense를 지원하나, 스트리밍되지 않음)
  • pipeToNodeWritable: 신규 API, 사용 추천(스트리밍으로 Full Suspense) 지원

 

ref

 

https://medium.com/naver-place-dev/react-18을-준비하세요-8603c36ddb25

 

React 18을 준비하세요.

요약

medium.com

https://yceffort.kr/2022/04/react-18-changelog#starttransition-usetransition

 

Home

yceffort

yceffort.kr

 

반응형

'Front-end > React' 카테고리의 다른 글

Suspense를 위한 wrapper 만들기  (0) 2022.07.28
react 17(개인 공부용)  (1) 2022.06.09
react TMI  (0) 2022.04.13
drag and drop으로 창 크기 조절  (0) 2022.03.18
redux, redux-saga로 로딩, 에러 페이지 구현  (0) 2022.02.12
반응형

JSX(JavaScript Syntax Extension and occasionally referred as JavaScript XML)

 

const element = <h1>{title}</h1>;

- JSX은 HTML가 아니라 js이므로 camelCase 사용

 

- React는 별도의 파일에 마크업 & 로직을 넣어 인위적으로 분리 대신

둘다 포함하는 '컴포넌트'라는 단위로 관심사를 분리

 

- JSX는 주입 공격 방지(렌더링 하기 이전에 문자열로 변환되어 XSS 방지)

 

- Babel은 JSX를 React.createElement() 호출로 컴파일

 

DangerouslySetInnerHTML

function createMarkup() {
  return {__html: 'First &middot; Second'};
}

function MyComponent() {
  return <div dangerouslySetInnerHTML={createMarkup()} />;
}

브라우저 DOM에서 innerHTML을 사용하기 위한 React의 대체 방법

* 사용은 하지만 innerHTML은 위험하다는 내용 상기

 

Rendered Element

 

- React Element들은 생성된 이후에 immutable

-> it represents the UI at a certain point in time.

 

State

 

- setState() state update는 비동기 처리 (State update May Be Asynchronous - React may batch multiple setState() calls into a single update for performance.)

 

- state Updates are merged

  constructor(props) {
    super(props);
    this.state = {
      posts: [],
      comments: []    
    };
  }

예를 들어 위와 같은 코드가 있을때

  componentDidMount() {
    fetchPosts().then(response => {
      this.setState({
        posts: response.posts      });
    });

    fetchComments().then(response => {
      this.setState({
        comments: response.comments      });
    });
  }

 

위와 같은 코드를 실행하면 상태 변경 merge됨 (The merging is shallow, so this.setState({comments}) leaves this.state.posts intact, but completely replaces this.state.comments.)

 

- 데이터는 단방향(아래로 흐른다)

 

Event

 

- 이벤트는 합성 이벤트

function Form() {
  function handleSubmit(e) {
    e.preventDefault();    console.log('You clicked submit.');
  }

  return (
    <form onSubmit={handleSubmit}>
      <button type="submit">Submit</button>
    </form>
  );
}

여기서 e는 리엑트 고유의 합성 이벤트(synthetic event)라 cross-browser 호환성을 걱정하지 않아도 된다

 

제어 컴포넌트 (Controlled Component)

<input>, <select> 등이 있을때 컴포넌트의 상태, props로 주어진 값을 활용하는 컴포넌트

ex) input 태그의 value 값을 useState로 제어)

 

비제어 컴포넌트

 

<input> 등이 자체적으로 상태를 갖는 경우 - (useRef등으로 관리)

해당 데이터와 UI의 동기가 이뤄지진 않으니 주의 (해당 상태가 변해도 컴포넌트의 상태가 변한게 아니므로 리렌더링이 일어나지 않는다)

 

ex) <input type="file"/> 의 경우 File API를 통해 js로 조작 가능한데 값이 읽기 전용이고 사용자만이 값 설정이 가능해서 비제어 컴포넌트

 

Key

 

가상돔 갱신할때 휴리스틱한 알고리즘으로 연산 속도를 돕는다

 

가정 : 

 

  • 서로 다른 타입의 두 엘리먼트는 서로 다른 트리를 만들어낸다.
  • 개발자가 key prop을 통해, 여러 렌더링 사이에서 어떤 자식 엘리먼트가 변경되지 않아야 할지 표시해 줄 수 있다.

 

비교대상 - sibling

배열의 index를 key로 사용시 뒤죽박죽 되므로 변하지 않고 예상 가능한 '유일값' 사용

 

Hook

 

클래스 컴포넌트에서 함수 컴포넌트로 바꾼 동기 요약

1. 간결하고(simplify) 빠르게 

2. 빠르게(performance)

3. 재사용성(Reusing logic & avoid Giant components & Confusing classes)

 

그외 이유 

1. 기존 클래스 컴포넌트에서는 컴포넌트간 로직의 재사용이 힘들었는데 

hook을 쓰면 상태 관련 로직을 재사용하기 쉽게 만들어준다.

-> 생명주기 메서드 기반으로 쪼개는것보다 hook을 통해 서로 비슷한 일을 하는 함수 묶음으로 컴포넌트를 나눈다.

 

2. 클래스 기반은 사람과 기계를 혼동시킨다

자바스크립트의 class와 this는 사람을 혼동시킨다.

-> hook은 class 없이 사용하는 방법을 제시

 

hook 규칙 

 

react hooks API은 hooks임을 네이밍에서부터 드러내기 위해 use-* prefix를 사용

 

1. 오직 React 내에서만 hook 호출

2. 최상위에서만 호출 

 

훅은 전역 배열로 관리되고 생성되는 순서에 따라 컴포넌트를 key로 해 인덱스로 관리

-> 항상 최상위에서 호출되야한다 (호출 순서 흐름이 항상 예상 가능해야한다)

function Ex(){
    const [a, setA] = useState(0);
    const [b, setB] = useState(0);
 
}

정확한 비유는 아닐 수 있지만.. 위 같은 예시는 내부적으로

[a, setA, b, setB ...];

이런식으로 저장될텐데 if 분기문같은 이유로 인해 hook 호출 순서가 바뀌면 원치 않은 값을 사용할 가능성이 생김

 

useEffect의 Effect란?

 

sideEffect 할때 그 Effect!

데이터 가져오기, dom 수동 수정, dom 수정 등 이 모든게 side Effect

리엑트 상태(FSM)와 연관 없는 부분을 side Effect라 부르는듯?

 

useRef

 

일종의 자바스크립트 객체값(plain object)를 반환(참조값)하기 때문에

리엑트의 상태 & 렌더링 생명주기와 연관없이 고유의 값을 가진다

(useRef 바뀌어도 리렌더링 되지 않는다)

 

reference

 

https://reactjs.org/

 

React – A JavaScript library for building user interfaces

A JavaScript library for building user interfaces

reactjs.org

 

 

반응형

'Front-end > React' 카테고리의 다른 글

react 17(개인 공부용)  (1) 2022.06.09
React18(개인 공부 메모용)  (0) 2022.06.09
drag and drop으로 창 크기 조절  (0) 2022.03.18
redux, redux-saga로 로딩, 에러 페이지 구현  (0) 2022.02.12
redux 기본 구조  (0) 2022.02.02
반응형

가끔 공부하다보면 anycast란 내용이 보이길래 요약겸 정리해논다.

 

Anycast

Anycast는 각각 동일한 IP 주소가 할당된 엔드포인트 그룹에 여러 라우팅 경로를 제공하는 기술 - microsoft

 

??? 이렇게 말하면 무슨 말인지 감이 잡히지 않는다.

 

보통 우리가 알고 있는 IP는 '고유한' 주소이고, Unicast IP이다. 

우선 unicast가 뭔지 알고 넘어가야 될꺼 같다.

 

참고)

그림 출처 : https://microchipdeveloper.com/tcpip:tcp-vs-udp

유니캐스트 (Unicast) - 1 : 1 

유니캐스트는 정보를 전송하기 위한 프레임에 자신의 MAC 주소와 목적지의 MAC 주소를 첨부하여 전송

 

브로드캐스트 (Broadcast) 1 : N

브로드캐스트 방식은 로컬 네트워크에 연결되어 있는 모든 시스템에게 프레임을 보내는 방식

 

멀티캐스트(Multicast) 1: N (특정 그룹)

멀티캐스트는 네트워크에 연결되어 있는 시스템 중 일부에게만 정보를 전송하는 것으로 특정 그룹에 속해 있는 시스템에게만 한 번에 정보를 전송할 수 있는 방법

라우터가 멀티캐스트를 지원해야만 사용 가능하다는 단점

멀티캐스트 전송이 지원되면 송신자는 여러 수신자에게 한 번에 메시지가 전송되도록 하여

데이터의 중복 전송으로 인한 네트워크 자원 낭비를 최소화할 수 있게 된다.

멀티캐스트 전송을 위해서는 헤더에 수신자의 주소 대신 수신자들이 참여하고 있는 그룹 주소를 표시하여 패킷을 전송한다.

 

Anycast란?

 

Anycast IP는 서로 다른 호스트끼리 동일한 IP 주소를 가질 수 있는 개념이다.

 

링크 계층(L2)에서 맥 주소를 보고 데이터를 전달할때는 충돌이 일어나면 사용이 불가능하지만

라우터(L3)에서는 네트워크 라우팅 알고리즘(BGP)을 통해 가장 가까운곳으로 판단되는 쪽으로 사용 가능한 식으로 구현되어 있다. 

 

anycast는 주로 DNS 서비스에 많이 활용되고 있다는데 지역별로 DNS 서버를 분산하고, 항상 네트워크 경로상 가까운 DNS 서버가 응답하게 된다.

 

왜 이런 구조를 사용하냐면 root DNS에 하위 DNS 서버들이 계층적으로 쌓여있는 기존 구조에서는 네트워크 DNS DDos 공격이나 웜 공격등으로 root DNS가 마비되게 되면 전 세계 DNS가 마비되게 된다. 그래서 DNS를 적절히 분산 구성해 분산 처리 및 가까운 거리로 인한 네트워크 지연 감소 등 여러 이유로 사용하고 있다고 한다.

 

가장 유명한 예시로는 구글의 public DNS IP 8.8.8.8 이 anycast로 구성되어 있고,

전세계 국가에 분산되어 있다고 한다. 

 

장점

- L4/L7 로드밸런싱 장비 대신 쓰기 가능?(라우팅+서버)

- 사용자와 네트워크 적으로 가장 가까운 곳으로 안내

- L4/L7 이 대규모 트래픽 처리가 힘든데 서버로 바로 트래픽을 보내니 대규모 트래픽 처리에 용이

- 회선문제로 장애시 자동으로 다른곳으로 우회(회선 이중화 비용 절감)

- 오픈소스 -> 가격 X!

 

단점

- 네트워크 적으로 가장 가까운곳 !== 지리적으로 가까운곳

ISP 마다 라우팅 정책이 다르므로 제어가 힘들다.

- 라우터에서 라우팅만 하기 때문에 L4/L7에선 가능한? 서버의 상태 체크(죽었나 살았나)가 안된다는 단점

 

reference 

 

https://docs.microsoft.com/ko-kr/windows-server/networking/dns/deploy/anycast

 

Anycast DNS 개요

이 항목에서는 Anycast DNS에 대한 간략한 개요를 제공합니다.

docs.microsoft.com

 

https://tech.kakao.com/2014/05/29/anycast/

 

kakao의 Anycast 활용 사례

Overview 네트워크 기술 하나 중 Anycast 는 DNS 서비스에서 주로 사용하고 있지만 KAKAO는 Anycast 기술을 확장하여 여러가지 어플리케이션 서비스에 사용되고 있습니다. 특히 서버에서 Quagga 오픈소스를

tech.kakao.com

 

반응형

'CS > 네트워크' 카테고리의 다른 글

URL & URI & URN  (0) 2022.02.27
HTTP 메소드 멱등성, 안전한 메소드  (0) 2022.01.31
[TCP] 3-way handshake와 4-way handshake  (0) 2022.01.23
Pooling, Long Pooling, Streaming  (0) 2022.01.23
반응형

*틀린 부분 있으면 피드백 주시면 감사하겠습니다~

 

async/await를 쓸줄은 아는데 정확히 어떻게 동작하는지 애매하게 알고 있어서 작성해봅니다.

 

동작 원리

 

const a = () => {
  console.log("a 시작");
  b();
  console.log("a 끝");
};

const b = async () => {
  console.log("b 시작");
  await c();
  console.log("b 끝");
};

const c = async () => {
  console.log("c 시작");
  await d();
  console.log("c 끝");
};

const d = () => {
  console.log("d")
};

a();

출처 : https://velog.io/@jjunyjjuny/JavaScript-asyncawait%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EB%8F%99%EC%9E%91%ED%95%A0%EA%B9%8C

 

이 코드를 이해하려면 일단 다음 부분에 대한 이해가 있어야한다.

 

- 자바스크립트의 비동기 처리방식

- 이벤트 루프와 테스크 큐, 마이크로 테스크 큐

- promise(ES6)와 async/await(ES8)

- async 함수는 항상 (명시적, 암묵적 방식으로) promise를 반환한다

 

자바스크립트는 비동기 함수를 처리하기 위해서 이벤트루프라는 방식을 사용하는데 이벤트 루프는 지금 콜스텍이 비었는지(실행하고 있는 task가 없는지)와 테스크 큐(들)에 지금 실행 가능한 task가 있는지를 반복적으로 확인한다. 그래서 비동기 함수는 큐에서 대기하다가 실행이 가능해지면 꺼내져와서 실행하는데, promise같은 경우에는 실행 우선 순위가 매우 높아서(마이크로 테스크큐) 실행 가능해지면 먼저 실행되게 된다.

 

async/await 함수의 동작 순서

 

1. await 키워드가 붙은 대상을 실행한다.

 

2. 1번 대상이 함수가 아니거나, 함수의 실행이 끝나면 '1번 대상을 실행한' async 함수를 일시정지하고 콜스텍에서 마이크로 테스크 큐에 옮긴다. 이때 await를 실행한 위치를 기억한다.

 

3. 지금 실행하고 있던 함수가 콜스텍에서 빠져나왔으니 다른 콜스텍을 실행한다. 

 

4. 콜스텍이 비었으면 2번에서 빠져 나왔던 async 함수를 다시 콜스택으로 옮겨 실행한다. 이때 await가 실행된 위치 다음부터 실행된다. 

 

5. 함수가 끝날때까지 반복...!

 

 

그래서 아까 문제를 다시 풀어보자면

 

1. a를 실행하고 콜스텍에 쌓인다 [a]

 

2. a 시작 출력 

 

3. b를 실행하고 콜스텍에 쌓인다 [a, b]

 

4. b 시작 출력

 

5. await keyword를 만났고 함수이므로 C를 실행하고 콜스텍에 쌓인다.  [a, b, c]

 

6. C 시작 출력

 

7.  await keyword를 만났고 함수이므로 D를 실행하고 콜스텍에 쌓인다.  [a, b, c, d]

 

8. D 출력

및 종료하고 콜스텍에서 빠져나온다. [a, b, c]

 

9. 7번에서 D를 시작했고 실행이 끝났으니 C는 마이크로 테스크큐에 들어가게 된다.  [a, b],  micro = [c]

 

10. 5번에서 C를 시작했고 9번에서 C가 일시정지 되었으므로 B도 마이크로 테스크 큐에 들어가게 된다.  [a],  micro = [c, b]

 

11. 콜스텍에서 B가 빠져나갔으므로 a가 이후 흐름을 실행한다.

a 끝 출력

a가 끝나서 콜스텍에서 빠져나온다. [], micro = [c, b]

 

12. 콜스텍에 비었으므로 이벤트루프가 마이크로 테스트큐에 있는 함수를 실행한다.

 

13. C 끝 출력 및 C가 콜스텍에서 빠져나온다. [], micro = [b]

 

14. B 끝 출력 및 b가 콜스텍에서 빠져나온다. [], micro = []

 

답 : 

a 시작
b 시작
c 시작
d
a 끝
c 끝
b 끝

 

결론 : 

async/await를 쓰면 가독성이 좋은 like-동기 방식으로 실행하는거처럼 보이지만 사실은 엄청 복잡한 비동기 방식으로 실행된다는것을 알게 되었다.  

 

 내부적 원리 요약

 

그래서 마이크로 테스크큐에 넣고 다시 콜스텍에서 실행될때 돌아올 위치를 어떻게 결정하는데? 의문이 떠올랐는데 Generator와 Promise의 원리를 섞어서 처리했다고 한다.

 

참고한 글) https://medium.com/sjk5766/async-await-%EC%9B%90%EB%A6%AC-cc643f18526d

async function fun() {
  await getDrink();
  await haveMeal();
  await drinkSoju();
}

예를 들어 위와 같은 코드가 있다면

 

function* fun() {
  yield getDrink(); // 1
  yield haveMeal(); // 2
  yield drinkSoju();// 3
}

위와 같은 함수로 변경되고 

yield를 만나 실행되고

내부에서 Promise 실행을 한 뒤 

Promise가 끝난다면 내부에서 resolve를 실행하고

Generator의 next()(step 함수 자체구현)를 호출해서 체인을 걸어주는식으로 동작한다고 한다. 

 

그런데 3년 전 글이라 실제로 바벨 홈페이지에 들어가서 돌려보니 (개념상으로는 비슷한데) 약간 달라진점이 있었다.

function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
  try {
    var info = gen[key](arg);
    var value = info.value;
  } catch (error) {
    reject(error);
    return;
  }
  if (info.done) {
    resolve(value);
  } else {
    Promise.resolve(value).then(_next, _throw);
  }
}

function _asyncToGenerator(fn) {
  return function () {
    var self = this,
      args = arguments;
    return new Promise(function (resolve, reject) {
      var gen = fn.apply(self, args);
      function _next(value) {
        asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'next', value);
      }
      function _throw(err) {
        asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'throw', err);
      }
      _next(undefined);
    });
  };
}

바벨을 돌려봤더니 위 코드를 보면 

 

step() 부분이 변경되어서

 

asyncGeneratorStep 안에서 만약 Generator가 끝난다면 (예를들어 코드 맨끝줄 상황) 그대로 resolve하는것은 동일한데 

아니라면 Promise의 then (Promise.resolve(value).then(_next, _throw);)을 사용해 첫번째 await 함수까지 실행하고 다음 체인은 마이크로 테스크큐에 넣어주는것으로 구현한것으로 보인다.

 

직접 해보고싶은 분들은 아래 주소로..?

 

https://babeljs.io/repl#?browsers=&build=&builtIns=false&corejs=3.6&spec=false&loose=false&code_lz=FAMwrgdgxgLglgewgAhgQwM4GsCMAKASgG9gBIKJDBAGwFMA6ahAczwHIZbsc2CBuZMmABfYKEixEKdNgBMhZCUEAnWjDDKUEWgHdkABWUIAtnAy08eVRgLIAvAD5ggl67fvkCx8nMwAKnDGtAhgMFZceBQQVHSMLOwyWLK8BAA0yDgADNkE_CJiwJgAntDI4NDwSMgARgpKLlExDEysbNU8ea5oOmhwMKiYuIR8zg2UNM3xbcmdyKTdvf2J8rPk47Et7NUAzLwjosCNE3GtGOjKMHvAtQSH65OttBAAJgD8V8BAA&debug=false&forceAllTransforms=false&shippedProposals=false&circleciRepo=&evaluate=false&fileSize=false&timeTravel=false&sourceType=module&lineWrap=true&presets=env&prettier=false&targets=&version=7.17.8&externalPlugins=&assumptions=%7B%7D 

 

Babel · The compiler for next generation JavaScript

The compiler for next generation JavaScript

babeljs.io

 

 

P.S) 바벨로 트렌스파일 말고 진짜 Generator로 변환하는가 찾아봤는데 V8 주석의 경우 변환한다고 적혀있긴 하다..

 

// ES#abstract-ops-async-function-await
// AsyncFunctionAwait ( value )
// Shared logic for the core of await. The parser desugars
//   await value
// into
//   yield AsyncFunctionAwait{Caught,Uncaught}(.generator_object, value)
// The 'value' parameter is the value; the .generator_object stands in
// for the asyncContext.

주석 발췌 from  https://github.com/v8/v8/blob/17a99fec258bcc07ea9fc5e4fabcce259751db03/src/builtins/builtins-async-function-gen.cc#L247-L254

 

reference

 

https://velog.io/@jjunyjjuny/JavaScript-asyncawait%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EB%8F%99%EC%9E%91%ED%95%A0%EA%B9%8C

 

[ JavaScript ] async/await는 어떻게 동작할까

await가 만드는 동기처럼 보이는 비동기 코드

velog.io

 

https://medium.com/sjk5766/async-await-%EC%9B%90%EB%A6%AC-cc643f18526d

 

async-await 원리

async-await 을 처음 봤을 때, 기존 call-back 구조와 비교해 소스를 가독성 좋고 간단하게 짤 수 있구나에 감탄했고 어떻게 이렇게 될까 라는 생각이 들었습니다. async-await은 내부적으로 Generator와 Promi

medium.com

 

 

반응형

'Front-end > JavaScript' 카테고리의 다른 글

commonjs와 ESM의 차이  (0) 2023.07.25
pnpm 도입기 (feat: 모노 레포)  (0) 2023.07.15
JS로 Single Page Application 구현  (0) 2022.03.12
Generator  (0) 2022.02.02
호이스팅과 var, let에 대하여  (0) 2022.01.29

반응형

https://blog.logrocket.com/implementing-repository-pattern-flutter/

* 레포지토리 패턴은 대부분 백엔드 내용이 많은데 프론트에도 쓰일 수 있나 해서 찾아본 글입니다!

듣기로는 백엔드에도 repository-service-controller 3계층으로 나누고 repository 계층에서 data source(DB)에 접근하는것으로 알고 있다.

 

이 글은 https://medium.com/backenders-club/consuming-apis-using-the-repository-pattern-in-vue-js-e64671b27b09를 개인 공부용으로 요약한 내용이고 틀린 오역이 있을수도 있습니다.

 

 

레포지토리 패턴이란?

 

데이터 출처에 관계없이 동일한 인터페이스로 접속할 수 있는 디자인 패턴 

보통 코드를 짜면 네트워크 요청을 할때 fetch/axios와 강한 결합도를 가지고 변경에 유연하지 않은데

 

중간에 인터페이스를 둬 

 

1. data acess code 재사용

2. (도메인별로 repositiory를 나눴을때) domain logic 사용이 쉬워짐 

3. logic의 결합도 감소

4. data access logic 과 business logic이 분리되어 테스트가 더 쉬워짐

5. DI의 개념이 추가됨 -> 테스트가 더 쉬워짐 

 

5개의 장점을 가질 수 있다.

 

4, 5번은 클린코드에서 말한

아직 존재하지 않는 코드를 사용하기
경계와 관련해 또 다른 유형은 아는 코드와 모르는 코드를 분리하는 경계다.
ex) 저쪽 팀이 아직 API를 설계하지 않았으므로 구체적인 방법은 모를때 구현을 미루고 이쪽 코드를 진행하기 위해 자체적으로 인터페이스를 정의한다. - 경계 part

경계를 구현하다보니 부수적으로 얻어지는 효과인거 같다. 

테스트시 or 백엔드에서 아직 구현이 안되었을시엔 프론트에서 mocking api를 사용하다 백엔드에서 구현이 완료되었을경우 손쉽게 갈아치울 수 있을걸로 보인다. 

 

// 03-28 추가

 

서비스워커에서 api 요청을 가로채서 프론트단에서 dummy data를 구현 안해도 되는 msw 라는걸 알게 되었다.

https://tech.kakao.com/2021/09/29/mocking-fe/

 

Mocking으로 생산성까지 챙기는 FE 개발

안녕하세요. 카카오엔터프라이즈 검색플랫폼프론트파트의 Lawrence.net입니다. 프론트엔드 개발 업무의 효율성을 높이기 위한 방법의 하나로 고민해 본 Mocking에 대해 설명하고 이를 적용했던 사례

tech.kakao.com

 

예제 코드

 

axiosclient.js

import axios from "axios";

const baseDomain = "https://jsonplaceholder.typicode.com";
const baseURL = `${baseDomain}`; // Incase of /api/v1;

// ALL DEFUALT CONFIGURATION HERE

export default axios.create({
  baseURL,
  headers: {
    // "Authorization": "Bearer xxxxx"
  }
});

 

우선 기본 axios를 정의한다.

 

repository.js

import Client from './Clients/AxiosClient';
const resource = '/posts';

export default class Repository {

	constructor({resource}){
		this.resource = resource;
    }

    get() {
        return Client.get(`${this.resource}`);
    },
    getPost(id) {
        return Client.get(`${this.resource}/${id}`);
    },
    create(payload) {
        return Client.post(`${this.resource}`, payload);
    },
    update(payload, id) {
        return Client.put(`${this.resource}/${id}`, payload);
    },
    delete(id) {
        return Client.delete(`${this.resource}/${id}`)
    },

    // MANY OTHER ENDPOINT RELATED STUFFS
};

기본 repository에 CRUD를 구현하고 필요시 상속 or 확장으로 메소드를 추가한다.

 

예를 들어 /user, /item, /car 등 여러 경로(도메인?)마다 기본 CRUD가 필요하다면 Repository를 상속만으로 각각 UserRepository, ItemRepositoy, CarRepository 를 사용해 기본 CRUD를 빠르게 구현할 수 있고 추가 메소드를 유연하게 붙여줄 수 있다.  

 

repositoryFactory.js

import PostRepository from './PostRepository'; // 만들어서 export?
import UserRepository from './UserRepository';

const repositories = {
    'posts': PostRepository,
    'users': UserRepository
}
export default {
    get: name => repositories[name]
};

레포지토리 생성은 팩토리 메소드 패턴을 이용한다.

각 도메인별로 이름을 붙이면 될 듯 하다.

 

Posts.js

<template>
  <div class="row">
    <Post v-for="(post, i) in posts" :key="i" :posts="post" />
    <div class="col-lg-8 col-md-10 mx-auto">
      <div class="clearfix">
        <a class="btn btn-primary float-right" href="#">Older Posts &rarr;</a>
      </div>
    </div>
  </div>
</template>

<script>
import Repository from "../repositories/RepositoryFactory";
const PostRepository = Repository.get("posts");

import Post from "./Post";
export default {
  name: "Posts",
  components: {
    Post
  },
  data() {
    return {
      posts: []
    };
  },
  created() {
    this.getPosts();
  },
  methods: {
    getPosts: async function() {
      const { data } = await PostRepository.get();
      this.posts = data;
    }
  }
};
</script>

Vue.js 예제인데 코드 흐름을 이해하는건 어렵진 않다.

사용하는 입장(Posts.js)에서는 레포지토리의 세부 사항을 알 필요가 없으므로 data access logic과 business logic이 분리되었다.

 

reference

 

https://blog.hanlee.io/2019/do-front-ends-dream-of-back-ends

 

프론트엔드는 백엔드의 꿈을 꾸는가?

점점 더 복잡해지는 프론트엔드와 백엔드의 유사점을 알아봅시다

blog.hanlee.io

 

https://blog.logrocket.com/implementing-repository-pattern-flutter/

 

Implementing a repository pattern In Flutter - LogRocket Blog

Write more manageable codebases for your Flutter apps by decoupling data access and business logic according to the repository design pattern.

blog.logrocket.com

https://medium.com/backenders-club/consuming-apis-using-the-repository-pattern-in-vue-js-e64671b27b09

 

Consuming APIs Using the Repository Pattern in Vue.js

in this article, we will be discussing how to consume API data with Vue.js using the Repository Pattern.

medium.com

 

반응형

'소프트웨어공학 > 디자인패턴' 카테고리의 다른 글

React Compound Component 패턴  (0) 2022.06.15
메모  (0) 2022.03.25
[행위] 책임 연쇄 패턴  (0) 2022.03.13
[행위] 전략 패턴 & 커맨드 패턴  (0) 2022.03.07
[행동] 중재자 패턴  (1) 2022.03.01

+ Recent posts