ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 리덕스 용어와 개념
    IT/리액트 2022. 8. 16. 17:32
    728x90

    상태 관리

    아래는 간단한 카운터 컴포넌트이다.

    function Counter() {
      // State: a counter value
      const [counter, setCounter] = useState(0)
    
      // Action: code that causes an update to the state when something happens
      const increment = () => {
        setCounter(prevCounter => prevCounter + 1)
      }
    
      // View: the UI definition
      return (
        <div>
          Value: {counter} <button onClick={increment}>Increment</button>
        </div>
      )
    }

    -       State: 앱을 구동하는 근원

    -       View: 현재 상태를 기반으로 하는 UI의 선언적 설명

    -       Actions: 사용자의 입력에 따라 발생하는 이벤트 및 상태를 업데이트하는 트리거

     

    이런 구조는 “one-way data flow”라고 한다

    -       State는 특적 시점의 앱 상태를 나타냄

    -       UI는 상태를 기반으로 렌더링함

    -       버튼 클릭과 같은 일이 발생하면 발생한 상황에 따라 상태를 업데이트함

    -       UI는 새 상태를 기반으로 다시 렌더링

    one-way data flow

    그러나 여러 컴포넌트에서 동일한 상태를 사용하고 공유해야 할 때, 특히 해당 컴포넌트들이 앱에서 서로 다른 부분에 존재하는 경우 단순성은 무너질 수 있다. 때때로 이것은 부모 컴포넌트로 상태를 끌어올리는 것으로 해결할 수 있지만 항상 도움되는 것은 아니다.

    (지금까지 해왔던 방식이었음. 그 결과 하나의 부모 컴포넌트에 너무 많은 상태가 존재하거나 해당 컴포넌트를 필요로하는 하위 컴포넌트를 위해 중간 컴포넌트가 불필요한 상태를 전달받고 전달해주는 문제가 있었음)

     

    이를 해결하는 한가지 방법은 공유 state를 컴포넌트에서 추출하고 컴포넌트 트리 외부의 중앙 위치에 두는 것이다. 이를 통해 컴포넌트 트리는 큰 view가 되는 것이고, 모든 컴포넌트는 트리의 위치와 상관없이 state에 접근하거나 액션을 취할 수 있음

     

    상태관리와 관련된 개념을 정의 및 분리하고 viewstate 간의 독립성을 유지하는 규칙을 적용해 코드에 더 많은 구조와 유지 관리성을 제공

     

    따라서 Redux 의 기본 아이디어는 애플리케이션의 전역 state를 포함한 하나의 중앙 집중형 장소와 코드를 예측 가능하게 만들기 위해 해당 상태를 업데이트할 때 따라야할 특정 패턴이다.

     

    불변성

    자바스크립트 객체와 배열은 기본적으로 모두 변경 가능하다.

    이것을 객체 또는 배열의 변형이라 한다. 메모리에 있는 동일한 객체 또는 배열 참조이지만 이제 객체 내부의 내용이 변경되었다.

    const obj = {
      a: {
        // To safely update obj.a.c, we have to copy each piece
        c: 3
      },
      b: 2
    }
    
    // spread operation
    const obj2 = {
      // copy obj
      ...obj,
      // overwrite a
      a: {
        // copy obj.a
        ...obj.a,
        // overwrite c
        c: 42
      }
    }
    
    // array method
    const arr = ['a', 'b']
    // Create a new copy of arr, with "c" appended to the end
    const arr2 = arr.concat('c')
    
    // or, we can make a copy of the original array:
    const arr3 = arr.slice()
    // and mutate the copy:
    arr3.push('c')

     

    값을 변경할 수 없도록 업데이트하려면 코드에서 기존 객체, 배열의 복사본을 만든 후 복사본을 수정해야 한다.

     

    자바스크립트의 스프레드 연산자와 배열 메소드(concat, split, …)를 이용해 직접 수행할 수 있다.

     

    리덕스는 모든 상태 업데이트가 불변적으로 수행되기를 기대한다.

     

    용어

    -       Actions

    타입 필드가 있는 일반 자바스크립트 객체이다. 액션은 애플리케이션에서 발생한 일을 설명하는 이벤트라고 생각할 수 있다.

    타입 필드는 작업에 설명적인 이름을 부여하는 문자열이어야 한다. 일반적으로 “domain/eventName” 형식으로 작성한다. 첫번째 부분은 이 작업이 속한 기능 또는 범주이고 두 번쨰 부분은 발생한 특정 일이다. Ex) todos/todoAdded

    액션 객체는 발생한 일에 대한 추가 정보가 있는 다른 필드를 가질 수 있다. 관습에 따라 페이로드라 불리는 필드에 해당 정보를 넣는다.

    const addTodoAction = {
      type: 'todos/todoAdded',
      payload: 'Buy milk'
    }

     

    -       Action creators

    액션 객체를 생성하고 반환하는 함수이다. 일반적으로 이것을 사용하므로 매번 손으로 작업 객체를 작성할 필요가 없다.

    const addTodo = text => {
      return {
        type: 'todos/todoAdded',
        payload: text
      }
    }

     

    -       Reducers

    현재의 상태와 액션 객체를 받고 필요한 경우 상태를 업데이트 하는 방법을 결정하고 갱신된 상태를 반환한다. 수신된 액션 유형에 따라 이벤트를 처리하는 이벤트 리스너로 생각할 수 있다.

    (state, action) => newState

     

    리듀서는 반드시 항상 특정 규칙을 따라야 한다.

    • State 및 action 인수를 기반으로 새 상태 값만 계산해야 한다.
    • 기존 상태를 수정하면 안된다. 대신, 기존 상태를 복사하고 복사된 값을 변경해 불변 갱신을 해야한다.
    • 비동기 로직을 수행하거나, 임의 값을 계산하거나, 사이드 이펙트를 발생시켜선 안된다.

    리듀서 함수 내부의 로직은 일반적으로 동일한 일련의 단계를 따른다.

    • 리듀서가 해당 액션에 관심이 있는지 확인
    • 그렇다면 상태의 복사본을 만들고 복사본을 새 값으로 업데이트한 다음 반환
    • 그렇지 않으면 기존 상태를 변경하지 않고 반환

    리듀서는 새 상태가 어떤 것이 되어야 하는지 결정하기 위해 내부에 모든 종류의 로직을 사용할 수 있다.

    const initialState = { value: 0 }
    
    function counterReducer(state = initialState, action) {
      // Check to see if the reducer cares about this action
      if (action.type === 'counter/increment') {
        // If so, make a copy of `state`
        return {
          ...state,
          // and update the copy with the new value
          value: state.value + 1
        }
      }
      // otherwise return the existing state unchanged
      return state
    }

     

    -       Store

    현재 리덕스 애플리케이션의 상태는 store라는 객체에 있다.

    Store는 리듀서를 전달하여 생성되며, 현재 상태 값을 반환하는 getState라는 메소드가 있다.

    import { configureStore } from '@reduxjs/toolkit'
    
    const store = configureStore({ reducer: counterReducer })
    
    console.log(store.getState())
    // {value: 0}

     

    -       Dispatch

    리덕스 스토어에는 dispatch라는 메소드가 있다. 상태를 갱신하는 유일한 방법은 store.dispatch()를 호출하고 액션 객체를 전달하는 것이다. 스토어는 해당 리듀서 함수를 실행하고 새로운 상태 값을 저장하며, getState를 호출해 갱신된 값을 검색할 수 있다.

    store.dispatch({ type: 'counter/increment' })
    
    console.log(store.getState())
    // {value: 1}

    디스패지 액션을 애플리케이션에서의 이벤트 트리거로 생각할 수 있다. 무슨 일이 일어났고, 스토어가 그것을 알기 원한다면 리듀서는 이벤트 리스너 처럼 동작하고 관심있는 액션을 감지했을 때 응답으로 상태를 업데이트한다.

    일반적으로 올바른 액션을 전달하기 위해 action creators를 호출한다.

    const increment = () => {
      return {
        type: 'counter/increment'
      }
    }
    
    store.dispatch(increment())
    
    console.log(store.getState())
    // {value: 2}

     

    -       Selectors

    Selectors는 스토어 상태 값에서 특정한 일부 정보를 추출하는 방법을 알고 있는 함수다. 앱이 커질수록, 다른 부분이 동일한 데이터를 읽어야 하므로 반복되는 로직을 피하는데 도움이 된다.

    const selectCounterValue = state => state.value
    
    const currentValue = selectCounterValue(store.getState())
    console.log(currentValue)
    // 2

     

    리덕스 애플리케이션 데이터 흐름

    리덕스는 앞서 나왔던 one-way data flow를 더 자세하게 쪼갤 수 있다.

     

    -       초기 설정

    • 리덕스 스토어는 루트 리듀서 메소드를 사용해 생성된다.
    • 스토어는 루트 리듀서를 한번 호출하고, 반환값을 초기 상태로 저장한다.
    • UI가 처음 렌더링 되면, UI 컴포넌트는 리덕스 스토어의 현재 상태에 액세스하고 무엇을 렌더링할지 결정하기 위해 해당 데이터를 사용합니다. 또한, 향후 스토어 업데이트를 구독하여 상태가 변경되었는지 알 수 있다.

    -       Update

    • 버튼 클릭과 같이 어떤 일이 앱에서 발생한다.
    • 앱 코드는 리덕스 스토어에 액션을 전달한다. Ex) dispatch({type: ‘counter/increment’})
    • 스토어는 이전 상태와 현재 액션으로 다시 리듀서 함수를 실행하고, 반환 값을 새 상태로 저장한다.
    • 스토어는 구독된 UI의 모든 부분에 스토어가 업데이트됐다고 알림
    • 스터어의 데이터가 필요한 각 UI 컴포넌트는 필요한 상태 부분이 변경되었는지 확인
    • 데이터가 변경된 각 컴포넌트는 새 데이터로 강제로 다시 렌더링되므로 화면에 표시된 내용을 업데이트할 수 있다.

    728x90

    'IT > 리액트' 카테고리의 다른 글

    리덕스 시작하기  (0) 2022.08.16
    리덕스란?  (0) 2022.08.16
    리액트 주요개념 - React로 사고하기  (0) 2022.01.16
    리액트 주요개념 - 합성 vs 상속  (0) 2022.01.16
    리액트 주요개념 - State 끌어올리기  (0) 2022.01.16

    댓글

Designed by Tistory.