Redux는 어떻게 작동합니까? (HTML 및 순수 JS만 해당)

23592 단어 reactreduxjavascript
이것은 HTML과 순수 자바스크립트만 있는 Redux의 코드 예제입니다. Code sandbox

<!DOCTYPE html>
<html>
  <head>
    <title>Redux basic example</title>
    <script src="https://unpkg.com/redux@latest/dist/redux.min.js"></script>
  </head>
  <body>
    <div>
      <p>
        Clicked: <span id="value">0</span> times
        <button id="increment">+</button>
        <button id="decrement">-</button>
        <button id="incrementIfOdd">Increment if odd</button>
        <button id="incrementAsync">Increment async</button>
      </p>
    </div>
    <script>
      function counter(state, action) {
        if (typeof state === 'undefined') {
          return 0
        }

        switch (action.type) {
          case 'INCREMENT':
            return state + 1
          case 'DECREMENT':
            return state - 1
          default:
            return state
        }
      }

      var store = Redux.createStore(counter)
      var valueEl = document.getElementById('value')

      function render() {
        valueEl.innerHTML = store.getState().toString()
      }

      render()
      store.subscribe(render)

      document.getElementById('increment')
        .addEventListener('click', function () {
          store.dispatch({ type: 'INCREMENT' })
        })

      document.getElementById('decrement')
        .addEventListener('click', function () {
          store.dispatch({ type: 'DECREMENT' })
        })

      document.getElementById('incrementIfOdd')
        .addEventListener('click', function () {
          if (store.getState() % 2 !== 0) {
            store.dispatch({ type: 'INCREMENT' })
          }
        })

      document.getElementById('incrementAsync')
        .addEventListener('click', function () {
          setTimeout(function () {
            store.dispatch({ type: 'INCREMENT' })
          }, 1000)
        })
    </script>
  </body>
</html>


웹페이지는 이렇게 생겼어요

  • createStore & counterReducer

  • // Counter reducer
    function counterReducer(state, action) {
        if (typeof state === 'undefined') {
            return 0;
        }
        switch (action.type) {
            case 'INCREMENT':
                return state + 1;
            case 'DECREMENT':
                return state - 1;
            default:
                return state;
        }
    }
    // Create store
    var store = Redux.createStore(counterReducer);
    

  • createStorecounterReducer 함수를 param으로 받고 store라는 객체를 반환합니다.
  • 이것은 정신 모델을 클래스로 사용하는 createStore 함수의 다이어그램입니다.


  • 다음은 simplified version of createStore in redux source code입니다.

    function createStore(reducer, initialState) {
      var currentReducer = reducer;
      var currentState = initialState;
      var listeners = [];
      var isDispatching = false;
    
      function getState() {
        return currentState;
      }
    
      function subscribe(listener) {
        listeners.push(listener);
    
        return function unsubscribe() {
          var index = listeners.indexOf(listener);
          listeners.splice(index, 1);
        };
      }
    
      function dispatch(action) {
        if (isDispatching) {
          throw new Error('Reducers may not dispatch actions.');
        }
    
        try {
          isDispatching = true;
          currentState = currentReducer(currentState, action);
        } finally {
          isDispatching = false;
        }
    
        listeners.slice().forEach(listener => listener());
        return action;
      }
    
      function replaceReducer(nextReducer) {
        currentReducer = nextReducer;
        dispatch({ type: '@@redux/INIT' });
      }
    
      dispatch({ type: '@@redux/INIT' });
    
      return { dispatch, subscribe, getState, replaceReducer };
    }
    


  • currentReducer = counterReducer
  • currentState = preloadedSate
  • 저장소가 생성되면 초기dispatch 작업 유형이 '@@redux/INIT'이므로 모든 감속기가 초기 상태를 반환합니다. counterReducer의 경우 0를 반환합니다.

  • 디스패치 함수 내부에서는 어떻게 됩니까?




    // Dispatch function inside Redux store
    function dispatch(action: A) {    
        currentState = currentReducer(currentState, action)
        const listeners = (currentListeners = nextListeners)
        for (let i = 0; i < listeners.length; i++) {
            const listener = listeners[i]
            listener()
        }
        return action
    }
    


  • currentReducer 함수가 호출되어 counterReducer
  • 작업 유형이 @@redux/INIT이고 currentStateundefined이므로 counterReducer는 저장소의 초기 상태인 0를 기본값으로 반환합니다.
  • 자, currentState0
  • 상태를 초기 값으로 업데이트한 후 알림을 위해 저장소를 구독하는 모든 수신기를 호출합니다.

  • var valueEl = document.getElementById('value')
    
    function render() {
      valueEl.innerHTML = store.getState().toString()
    }
    
    render()
    store.subscribe(render)
    


  • 이 경우에는 render() 함수가 있으며, 이 함수는 다시 호출되어 DOM 요소를 초기 값으로 업데이트합니다.
  • 이제 브라우저에서 표시된 숫자0를 선택합니다.

  • 조치가 전송될 때 상태 업데이트




    document.getElementById('increment')
        .addEventListener('click', function () {
          store.dispatch({ type: 'INCREMENT' })
        })
    


  • 사용자가 "+"버튼을 클릭하면 store는 store의 reducer에 'INCREMENT' 유형의 action을 디스패치하며 흐름은 위 설명과 동일합니다.
  • 함수 currentReducer는 상태가 0이고 작업 유형이 'INCREMENT'인 상태에서 호출됩니다.
  • 'INCREMENT'counterReducer 함수 내부의 케이스이기 때문에 이제 새 상태는 0 + 1와 같고 저장소 상태로 돌아갑니다.
  • 그런 다음 상태가 성공적으로 업데이트되었음을 ​​알리기 위해 다시 청취자에게 알립니다.
  • 이제 화면에 Clicked: 1 times
  • 가 표시됩니다.
  • 흐름이 다른 작업 유형과 유사함

  • 이것이 기본적으로 Redux가 내부에서 작동하는 방식입니다. 실제 프로젝트에서 Redux 스토어에는 reducersmidleware가 여러 개 있을 수 있으며 타사 라이브러리는 Redux 작업 흐름을 향상시킵니다. 그러나 핵심은 기본적으로 작동하는 방식입니다!

    좋은 웹페이지 즐겨찾기