분류 Reactjs

24 줄의 JavaScript로 Redux를 구현하는 방법

컨텐츠 정보

  • 조회 393 (작성일 )

본문

How to Implement Redux in 24 Lines of JavaScript 


https://www.freecodecamp.org/news/redux-in-24-lines-of-code/ 


90 % 컨벤션, 10 % 라이브러리 


Redux는 지금까지 만들어진 가장 중요한 JavaScript 라이브러리 중 하나입니다. FluxElm과 같은 선행 기술에서 영감을 얻은 Redux는 세 가지 간단한 포인트로 확장 가능한 아키텍처를 도입하여 JavaScript 함수 프로그래밍을 맵에 추가했습니다.


Redux를 처음 사용하는 경우 공식 문서를 먼저 읽어보십시오.


Redux는 대부분 컨벤션입니다 


Redux 아키텍처를 사용하는 이 간단한 카운터 응용 프로그램을 고려하십시오. 앞으로 점프하고 싶다면 Github 저장소를 확인하십시오.


redux-counter-app-demo 


State는 하나의 나무에 산다 


응용 프로그램의 상태는 다음과 같습니다.


const initialState = { count: 0 };


Actions은 상태 변경을 선언합니다 


Redux 규칙에 따라 상태를 직접 수정 (변경)하지 않습니다.

// DON'T do this in a Redux app
state.count = 1;

대신 사용자가 응용 프로그램에서 활용할 수 있는 모든 action을 만듭니다.


const actions = {
  increment: { type: 'INCREMENT' },
  decrement: { type: 'DECREMENT' }
};

Reducer는 action을 해석하고 state를 업데이트합니다 


마지막 아키텍처 부분은 이전 상태와 action을 기반으로 상태의 새 복사본을 반환하는 순수한 함수인 reducer를 요구합니다.

  • 증가(increment)가 발생하면 state.count를 증가시킵니다.
  • 감소(decrement)가 발생하면 state.count를 감소시킵니다.
const countReducer = (state = initialState, action) => {
  switch (action.type) {
    case actions.increment.type:
      return {
        count: state.count + 1
      };

    case actions.decrement.type:
      return {
        count: state.count - 1
      };

    default:
      return state;
  }
};

지금까지 Redux 없음 


Redux 라이브러리를 아직 건드리지 않았다는 것을 알고 계셨습니까? 방금 일부 객체와 함수를 만들었습니다. 이것이 바로 "대부분의 관례"라는 의미입니다. Redux의 90 %에는 Redux가 필요하지 않습니다!


Redux를 구현하자 


이 아키텍처를 사용하려면 Store에 연결해야 합니다. 우리는 createStore라는 하나의 함수만 구현할 것입니다.


이런 식으로 사용됩니다.


import { createStore } from 'redux'

const store = createStore(countReducer);

store.subscribe(() => {
  console.log(store.getState());
});

store.dispatch(actions.increment);
// logs { count: 1 }

store.dispatch(actions.increment);
// logs { count: 2 }

store.dispatch(actions.decrement);
// logs { count: 1 }

그리고 여기에 초기 상용구가 있습니다. 리스너 목록과 리듀서가 제공 한 초기 상태가 필요합니다.


const createStore = (yourReducer) => {
    let listeners = [];
    let currentState = yourReducer(undefined, {});
}

누군가가 store을 구독 할 때마다 리스너 배열에 추가됩니다. 누군가가 액션을 디스패치 할 때마다 모든 리스너에게 루프로 통지해야 하기 때문에 이는 중요합니다.


undefined 빈 객체로 yourReducer를 호출하면 위에 설치 한 initialState가 반환됩니다. 이것은 store.getState()를 호출 할 때 반환 할 적절한 값을 제공합니다. 말하자면, 그 방법을 만들어 봅시다.


store.getState() 


스토어에서 최신 상태를 반환하는 함수입니다. 사용자가 버튼을 클릭 할 때마다 UI를 업데이트 하려면 이 함수가 필요합니다.


const createStore = (yourReducer) => {
    let listeners = [];
    let currentState = yourReducer(undefined, {});
    
    return {
        getState: () => currentState
    };
}

store.dispatch(action) 


매개 변수로 조치를 취하는 함수입니다. 새 액션을 얻기 위해 해당 액션과 currentState를 yourReducer에 제공합니다. 그런 다음 dispatch는 store에 가입 한 모든 사람에게 알립니다.

const createStore = (yourReducer) => {
  let listeners = [];
  let currentState = yourReducer(undefined, {});

  return {
    getState: () => currentState,
    dispatch: (action) => {
      currentState = yourReducer(currentState, action);

      listeners.forEach((listener) => {
        listener();
      });
    }
  };
};

store.subscribe(listener) 


이것은 store가 조치를 수신 할 때 알림을 받을 수 있게 하는 함수입니다. 여기에서 store.getState()를 사용하여 최신 상태를 얻고 UI를 업데이트하는 것이 좋습니다.

const createStore = (yourReducer) => {
  let listeners = [];
  let currentState = yourReducer(undefined, {});

  return {
    getState: () => currentState,
    dispatch: (action) => {
      currentState = yourReducer(currentState, action);

      listeners.forEach((listener) => {
        listener();
      });
    },
    subscribe: (newListener) => {
      listeners.push(newListener);

      const unsubscribe = () => {
        listeners = listeners.filter((l) => l !== newListener);
      };

      return unsubscribe;
    }
  };
};

subscribe는 더 이상 store의 업데이트를 듣고 싶지 않을 때 호출 할 수 있는 구독 취소라는 함수를 반환합니다.


All Together Now 


이것을 버튼에 연결하고 최종 소스 코드를 봅시다.


// simplified createStore function
const createStore = (yourReducer) => {
  let listeners = [];
  let currentState = yourReducer(undefined, {});

  return {
    getState: () => currentState,
    dispatch: (action) => {
      currentState = yourReducer(currentState, action);

      listeners.forEach((listener) => {
        listener();
      });
    },
    subscribe: (newListener) => {
      listeners.push(newListener);

      const unsubscribe = () => {
        listeners = listeners.filter((l) => l !== newListener);
      };

      return unsubscribe;
    }
  };
};

// Redux architecture pieces
const initialState = { count: 0 };

const actions = {
  increment: { type: 'INCREMENT' },
  decrement: { type: 'DECREMENT' }
};

const countReducer = (state = initialState, action) => {
  switch (action.type) {
    case actions.increment.type:
      return {
        count: state.count + 1
      };

    case actions.decrement.type:
      return {
        count: state.count - 1
      };

    default:
      return state;
  }
};

const store = createStore(countReducer);

// DOM elements
const incrementButton = document.querySelector('.increment');
const decrementButton = document.querySelector('.decrement');

// Wire click events to actions
incrementButton.addEventListener('click', () => {
  store.dispatch(actions.increment);
});

decrementButton.addEventListener('click', () => {
  store.dispatch(actions.decrement);
});

// Initialize UI display
const counterDisplay = document.querySelector('h1');
counterDisplay.innerHTML = parseInt(initialState.count);

// Update UI when an action fires
store.subscribe(() => {
  const state = store.getState();

  counterDisplay.innerHTML = parseInt(state.count);
});

그리고 다시 한 번 마지막 UI가 있습니다.


redux-counter-app-demo 


내가 사용한 HTML / CSS에 관심이 있다면 GitHub 리포지토리가 다시 있습니다!