redux 및 react-redux 간단 한 실현

앞 에 쓰다
redux 프로필
자 바스 크 립 트 단일 페이지 응용 개발 이 갈수 록 복잡 해 지면 서 자 바스 크 립 트 는 그 어느 때 보다 많은 state(상태)를 관리 해 야 합 니 다.이 state 는 서버 응답,캐 시 데이터,로 컬 생 성 이 서버 에 오래 지속 되 지 않 은 데 이 터 를 포함 할 수 있 으 며,UI 상태 도 포함 할 수 있 습 니 다.예 를 들 어 활성 화 된 경로,선 택 된 탭,로 딩 효과 나 페 이 퍼 를 표시 할 지 여부 등 입 니 다.
끊임없이 변화 하 는 state 를 관리 하 는 것 은 매우 어렵다.만약 에 하나의 model 의 변화 가 다른 model 변 화 를 일 으 킬 수 있다 면 view 가 변화 할 때 대응 하 는 model 과 다른 model 의 변 화 를 일 으 킬 수 있 고 순서대로 다른 view 의 변 화 를 일 으 킬 수 있다.무슨 일이 일 어 났 는 지 알 수 없 을 때 까지state 가 언제,어떤 이유 로,어떻게 변화 하 는 지 는 이미 통제 되 지 않 습 니 다.시스템 이 복잡 해 지면 문 제 를 재현 하거나 새로운 기능 을 추가 하기 가 어려워 진다.
만약 에 이것 이 나 쁘 지 않다 면 전단 개발 분야 에서 온 새로운 수 요 를 고려 해 야 한다.예 를 들 어 업데이트,서버 렌 더 링,경로 전환 전 요청 데이터 등 이다.전단 개발 자 들 이 전례 없 는 복잡성 을 겪 고 있 는데 이대로 포기 하 는 것 일 까?아니 지.
이곳 의 복잡성 은 어느 정도 에 우 리 는 항상 정리 하기 어 려 운 두 개념 을 한데 혼동한다.변화 와 비동기 이다.둘 을 나 누 면 잘 할 수 있 지만 섞 이면 엉망 이 된다.일부 라 이브 러 리 는 React 와 같은 보기 층 에서 비동기 와 DOM 을 직접 조작 하여 이 문 제 를 해결 하려 고 합 니 다.옥 에 티 는 React 가 여전히 state 의 데 이 터 를 처리 하 는 문 제 를 우리 자신 에 게 남 겨 두 었 다 는 점 이다.redux 는 이 상 태 를 관리 해 줄 수 있 습 니 다.
데모 데모 데모

demo 구조 트 리

├── config-overrides.js
├── .gitignore
├── package.json
├── package-lock.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json
├── README.md
└── src
 ├── App.js
 ├── Demo
 │ ├── actionCreate.js
 │ ├── Demo.jsx
 │ ├── react-redux.js
 │ ├── reducer.js
 │ ├── redux.js
 │ ├── style.css
 │ └── thunk.js
 └── index.js
1.redux API createStore 의 실현
  먼저 우 리 는 reducer 와 action 의 지식 을 결합 하여 처음에 보 여 준 demo 를 간단하게 실현 하고 createStore 의 신비 한 베일 을 점차적으로 밝 혔 다.
1.1 준비 작업:
reducer 를 만 들 고 reducer 내 보 내기

// reducer.js
const initState = { user: 'qianyin', age: 18, sex: ' ' };
export const reducer = (state=initState, action) => {
 switch(action.type){
 case 'USER_UPDATE':
  return {...state, ...action.payload};
 case 'AGE_GROW':
  return {...state, age: state.age + 1};
 case 'SEX_UPDATE':
  return {...state, ...action.payload};
 default:
  return state;
 }
}
액 션 생 성 함수 생 성

// actionCreate.js
export const changeUser = (user) => {
 return {
 payload:{user},
 type: 'USER_UPDATE',
 };
}

export const changeAge = () => {
 return { type: 'AGE_GROW' };
}
react 를 통 해 페이지 에 기본 요 소 를 미리 그립 니 다.

/* style.css */
.btn{
 height: 31px;

}
.input{
 height: 25px;
}

// Demo.jsx
import React from 'react';
import './style.css';

export default class Demo extends React.Component{
 onChange = () => {}
 onClick = () => {}
 render(){
 return (
  <div>
  <p>user: xxx, age: xxx</p>
  user: 
  <input type="text" className="input" onChange={this.onChange}/>
  &nbsp;
  <button className="btn" onClick={this.onClick}>    </button>
  </div>
 );
 }
}
최종 페이지 는 다음 과 같이 보 여 줍 니 다:

1.2 데모 의 첫 구현 코드
  • 전역 상태 state 만 들 기;
  • 감청 대기 열 만 들 기;
  • 감청 대기 열 에 대해 지정 한 감청 대상 을 대기 열 에 추가 하 는 함 수 를 추가 합 니 다
  • 함수 dispatch 에서 reducer 를 실행 하면 반환 값 을 새로운 state 로 하고 감청 대상 을 순서대로 실행 합 니 다
  • dispatch 에서 주어진 type 이 상대 적 으로 유일한 action 을 기본 으로 실행 합 니 다.reducer 의 기본 상태 값 과 일치 하여 redux state 에 대한 초기 화 를 실현 하 는 것 이 목적 입 니 다
  • 구성 요소 Demo 에서 함수 update 를 통 해 this.setState 를 사용 하여 전역 state 를 react state 에 저장 하고 함수 update 를 감청 대기 열 에 추가 합 니 다.따라서 우리 가 dispatch 를 통 해 전체 상 태 를 수정 하려 고 할 때 react state 를 신속하게 업데이트 하여 최종 적 으로 react 수명 주기 render 를 촉발 할 수 있 습 니 다
  • react 생명주기 componentDidMount 에서 저 희 는 update 를 감청 대기 열 에 추가 하 는 것 외 에 update 를 수 동 으로 실행 해 야 합 니 다.그 주요 목적 은 react state 를 처음으로 초기 화 하 는 것 입 니 다
  • 
    // Demo.jsx
    import React from 'react';
    import { changeAge, changeUser } from './actionCreate';
    import { reducer } from './reducer';
    import './style.css';
    
    let state;
    const listeners = [];
    const subscribe = (listener) => {
     listeners.push(listener);
    }
    const dispatch = (action) => {
     state = reducer(state, action);
     console.log(state);
     listeners.forEach(v => v());
    }
    dispatch({type: '%$&HJKAJJHDJHJ'});
    
    export default class Demo extends React.Component{
     state = {user: 'xxx', age: 'xxx'};
     componentDidMount(){
     subscribe(this.update);
     this.update();
     }
    
     update = () => {
     this.setState(state);
     }
    
     onChange = (e) => {
     dispatch(changeUser(e.target.value));
     }
    
     onClick = () => {
     dispatch(changeAge());
     }
    
     render(){
     return (
      <div>
      <p>user: {this.state.user}, age: {this.state.age}</p>
      user: 
      <input type="text" className="input" onChange={this.onChange}/>
      &nbsp;
      <button className="btn" onClick={this.onClick}>    </button>
      </div>
     );
     }
    }
    1.3 API createStore 의 실현
    사실 위의 코드 에서 createStore 의 실현 원리 에 대해 기본적으로 설명 하고 제 거 했 습 니 다.아래 에 우 리 는 단순히 코드 에 대해 간단 한 패 키 징 을 했 을 뿐 입 니 다.물론 state 를 얻 기 위해 함수 getState 를 추가 하여 이 를 실현 합 니 다.
    createStore 함수 구현
    
    // redux.js
    
    export const createStore = (reducer) => {
     //     
     let state;
     const listeners = [];
    
     //     
     const getState = () => {
     return state;
     }
    
     //       
     const subscribe = (listener) => {
     listeners.push(listener);
     }
    
     // [1]  reducer     [2]        
     const dispatch = (action) => {
     state = reducer(state, action);
     listeners.forEach(v => v());
     }
    
     //     state
     dispatch({type: '%$&HJKAJJHDJHJ'});
     
     //     
     return {getState, subscribe, dispatch};
    }
    createStore 를 호출 하고 demo 를 수정 합 니 다.
    
    // Demo.jsx
    import React from 'react';
    import './style.css';
    import { changeAge, changeUser } from './actionCreate';
    import { reducer } from './reducer';
    import { createStore } from './redux';
    
    const store = createStore(reducer);
    
    export default class Demo extends React.Component{
     state = {user: 'xxx', age: 'xxx'};
     componentDidMount(){
     store.subscribe(this.update);
     this.update();
     }
    
     update = () => {
     this.setState(store.getState());
     }
    
     onChange = (e) => {
     store.dispatch(changeUser(e.target.value));
     }
    
     onClick = () => {
     store.dispatch(changeAge());
     }
    
     render(){
     return (
      <div>
      <p>user: {this.state.user}, age: {this.state.age}</p>
      user: 
      <input type="text" className="input" onChange={this.onChange}/>
      &nbsp;
      <button className="btn" onClick={this.onClick}>    </button>
      </div>
     );
     }
    }
    2.react-redux API Provider 의 실현
    react 에서 대부분 상황 에서 우 리 는 상 태 를 후대 구성 요소 에 전달 하여 사용 해 야 합 니 다.물론 props 를 통 해 상 태 를 아버지 급 에서 서브 급 으로 전달 할 수 있 지만 상태 가 전달 해 야 할 등급 이 비교적 깊 은 상황 에서 props 를 사용 하면 무력 해 집 니 다.그러면 react-redux 에서 store 에 대한 전달 을 어떻게 실현 합 니까?
    2.1 react context 의 도입
    App.js 에 store 를 만 들 고 context 를 통 해 store 를 전달 합 니 다.
    
    // App.js
    import React, { Component } from 'react';
    import propTypes from 'prop-types';
    import { createStore } from './Demo/redux';
    import { reducer } from './Demo/reducer';
    import Demo from './Demo/Demo';
    
    //    store
    const store = createStore(reducer);
    
    class App extends Component {
     //    childContextTypes       
     static childContextTypes = {
     store: propTypes.object
     };
     //    childContext
     getChildContext(){
     return {store}
     }
     render() {
     return <Demo />;
     }
    }
    export default App;
    하위 구성 요소 데모 에서 context 를 통 해 store 를 가 져 오고 코드 를 간단하게 수정 합 니 다.
    
    // Demo.jsx
    import React from 'react';
    import propTypes from 'prop-types';
    import './style.css';
    import { changeAge, changeUser } from './actionCreate';
    
    export default class Demo extends React.Component{
     //    context      
     static contextTypes = {
     store: propTypes.object
     };
    
     constructor(props, context){
     super(props, context);
     //   store
     this.store = context.store;
     this.state = {user: 'xxx', age: 'xxx'};
     }
     
     componentDidMount(){
     this.store.subscribe(this.update);
     this.update();
     }
    
     update = () => {
     this.setState(this.store.getState());
     }
    
     onChange = (e) => {
     this.store.dispatch(changeUser(e.target.value));
     }
    
     onClick = () => {
     this.store.dispatch(changeAge());
     }
    
     render(){
     return (
      <div>
      <p>user: {this.state.user}, age: {this.state.age}</p>
      user: 
      <input type="text" className="input" onChange={this.onChange}/>
      &nbsp;
      <button className="btn" onClick={this.onClick}>    </button>
      </div>
     );
     }
    }
    2.2 패 키 징 코드 구현 Provider
    react context 를 통 해 저 희 는 store 에 대한 전달 을 실 현 했 습 니 다.여기 서 Provider 의 기능 과 실현 원 리 는 대체적으로 뚜렷 한 편 입 니 다.구성 요 소 를 소포 하 는 동시에 react context 를 통 해 공유 store 를 전달 하 는 것 이 아 닙 니 다.그러면 다음 에 우 리 는 코드 에 대한 패 키 징 을 통 해 Provider 구성 요 소 를 실현 합 니 다.
    Provider 구성 요소:store 에 대한 전달 실현
    
    // react-redux.js
    import React from 'react';
    import propTypes from 'prop-types';
    
    export class Provider extends React.Component{
     //    childContext      
     static childContextTypes = {
     store: propTypes.object
     };
    
     //    childContext
     getChildContext(){
     return {store: this.props.store}
     }
     
     render(){
     return this.props.children;
     }
    }
    App.js 다시 쓰기:Provider 구성 요소 호출
    
    // App.js
    import React, { Component } from 'react';
    import { createStore } from './Demo/redux';
    import { Provider } from './Demo/react-redux';
    import { reducer } from './Demo/reducer';
    import Demo from './Demo/Demo';
    
    //    store
    const store = createStore(reducer);
    
    class App extends Component {
     render() {
     //      Provider
     return <Provider store={store}><Demo /></Provider>;
     }
    }
    export default App;
    3.react-redux API connect 고급 구성 요소 의 실현
    위의 글 에서 후대 구성 요소 가 store 를 가 져 오 려 면 react context 를 수 동 으로 가 져 와 store 를 호출 하고 외 현적 으로 store 내 부 를 호출 하 는 방법 이 필요 합 니 다.다음 에 우 리 는 이러한 고급 구성 요소 connect 를 실현 합 니 다.우 리 는 필요 한 redux state 와 action 생 성 함수 만 제공 하면 props 를 통 해 해당 하 는 redux state 를 얻 을 수 있 고 props 를 통 해 action 생 성 함 수 를 직접 호출 하여 redux state 를 수정 할 수 있 습 니 다.
    고급 구성 요소 connect 만 들 기
    
    // react-redux.js
    export const connect = (mapStateToProps, mapDispatchToProps) => (Component) => {
     return class NewComponent extends React.Component{
     render(){
      return <Component />
     }
     }
    }
    저장 소 가 져 오기
    
    // react-redux.js
    export const connect = (mapStateToProps, mapDispatchToProps) => (Component) => {
     return class NewComponent extends React.Component{
     //    context      
     static contextType = {
      store: propTypes.object
     };
      // [1]   store [2]    react state
     constructor(props, context){
      super(props, context);
      this.store = context.store;
      this.state = {};
     }
     render(){
      return <Component />
     }
     }
    }
    감청 대상 을 추가 하고 props 를 통 해 하위 구성 요소 에 상 태 를 전달 하려 고 시도 합 니 다.
    
    export const connect = (mapStateToProps, mapDispatchToProps) => (Component) => {
     return class NewComponent extends React.Component{
     static contextType = {
      store: propTypes.object
     };
     constructor(props, context){
      super(props, context);
      this.store = context.store;
      this.state = {};
     }
      // [1]       [2]        ,    react state
     componentDidMount(){
      this.store.subscribe(this.update);
      this.update();
     }
     
     update = () => {
      //     redux state      react state
      const state = this.store.getState();
      this.setState(state);
     }
     render(){
      //    props   react state        
      return <Component {...this.state} />
     }
     }
    }
    mapStateToProps 를 통 해 지정 한 redux state 가 져 오기
    
    // react-redux.js
    export const connect = (mapStateToProps, mapDispatchToProps) => (Component) => {
     return class NewComponent extends React.Component{
     static contextType = {
      store: propTypes.object
     };
     constructor(props, context){
      super(props, context);
      this.store = context.store;
      this.state = {};
     }
     componentDidMount(){
      this.store.subscribe(this.update);
      this.update();
     }
     
     update = () => {
      //    mapStateToProps            state
      const state = this.store.getState();
      const filterState = mapStateToProps(state);
      this.setState(filterState);
     }
     render(){
      return <Component {...this.state} />
     }
     }
    }
    mapDispatchToProps 를 통 해 action 생 성 함수 가 져 오기:dispatch 소 포 를 사용 한 후 되 돌려 줍 니 다.
    
    // react-redux.js
    // react-redux.js
    export const connect = (mapStateToProps, mapDispatchToProps) => (Component) => {
     return class NewComponent extends React.Component{
     static contextTypes = {
      store: propTypes.object
     };
     constructor(props, context){
      super(props, context);
      this.store = context.store;
      this.state = {};
     }
     componentDidMount(){
      this.store.subscribe(this.update);
      this.update();
     }
     
     update = () => {
      //    state ===>         state
      const state = this.store.getState();
      const filterState = mapStateToProps(state);
    
      //    dispatch   mapDispatchToProps    action            
      const actionFun = {};
      for(let key in mapDispatchToProps){
      actionFun[key] = (...args) => {
       this.store.dispatch(mapDispatchToProps[key](...args));
      }
      }
     //       :    
     // const actionFun = Object.keys(mapDispatchToProps)
     // .reduce((total, item) => {
     // return { ...total, [item]: (...args) => {dispatch(mapDispatchToProps[item](...args));}
     // } } ,{});
    
      this.setState({...filterState, ...actionFun});
     }
     render(){
      return <Component {...this.state} />
     }
     }
    }
    고급 구성 요소 호출:데모.jsx 수정
    
    // Demo.jsx
    import React from 'react';
    import { changeAge, changeUser } from './actionCreate';
    import { connect } from './react-redux';
    import './style.css';
    
    //    mapStateToProps    redux state       redux state
    const mapStateToProps = (state) => {
     return {user: state.user, age: state.age};
    }
    
    //       
    @connect(mapStateToProps, {changeAge, changeUser})
    export default class Demo extends React.Component{
     onChange = (e) => {
     this.props.changeUser(e.target.value);
     }
     onClick = () => {
     this.props.changeAge();
     }
     render(){
     return (
      <div>
      <p>user: {this.props.user}, age: {this.props.age}</p>
      user: 
      <input type="text" className="input" onChange={this.onChange}/>
      &nbsp;
      <button className="btn" onClick={this.onClick}>    </button>
      </div>
     );
     }
    }
    4.redux API bidactioncreators 의 실현
    위 에서 우리 가 mapDispatchToProps 에 대한 처리 과정 은 API bindactioncreators 의 기능 입 니 다.주어진 action 생 성 함 수 를 dispatch 로 패키지 한 후 되 돌려 줍 니 다.
    패키지 bindactioncreators
    
    // redux.js
    export const bindactioncreators = (mapDispatchToProps, dispatch) => {
     const actionFun = {};
     //    mapDispatchToProps     action          dispatch      
     for(let key in mapDispatchToProps){
     actionFun[key] = (...args) => {
      dispatch(mapDispatchToProps[key](...args));
     }
     }
    
     return actionFun;
     //       :    
     // return actionFun = Object.keys(mapDispatchToProps)
     // .reduce((total, item) => {
     // return { ...total, [item]: (...args) => {dispatch(mapDispatchToProps[item](...args));}
     // } } ,{});
    }
    수정 connect:
    
    // react-redux.js
    import { bindactioncreators } from './redux';
    ....
    export const connect = (mapStateToProps, mapDispatchToProps) => (Component) => {
     return class NewComponent extends React.Component{
     static contextTypes = {
      store: propTypes.object
     };
     constructor(props, context){
      super(props, context);
      this.store = context.store;
      this.state = {};
     }
     componentDidMount(){
      this.store.subscribe(this.update);
      this.update();
     }
     
     update = () => {
      const state = this.store.getState();
      const filterState = mapStateToProps(state);
      
      //    API bindactioncreators 
      //   mapDispatchToProps     action        dispatch        
      const actionFun = bindactioncreators(mapDispatchToProps, this.store.dispatch);
      this.setState({...filterState, ...actionFun});
     }
     render(){
      return <Component {...this.state} />
     }
     }
    }
    5.redux API apply Middleware 의 실현
    이 간략화 판 의 react-redux 는 이미 초보 적 으로 완 성 된 것 이 라 고 할 수 있 습 니 다.그러나 만약 에 우리 가 우리 의 age 값 의 증 가 를 원 하 는 것 은 비동기 작업 입 니 다.예 를 들 어 단 추 를 누 른 후에 2 초 후에 age 를 수정 하 는 것 이지 단 추 를 누 르 면 바로 값 을 수정 하 는 것 이 아 닙 니 다.이렇게 되면 우 리 는 어떻게 실현 해 야 합 니까?
    물론 우 리 는 setTimeout 을 통 해 2 초 후에 action 생 성 함 수 를 실행 할 수 있 습 니 다.예 를 들 어 다음 과 같 습 니 다.
    
    onClick = () => {
     setTimeout(()=>{
      //       action     
      this.props.changeAge();
     }, 2000);
    }
    그러나 사실은 우 리 는 위 와 같이 그렇게 정돈 하 는 것 을 원 하지 않 는 다.우 리 는 이러한 효 과 를 원한 다.우 리 는 action 생 성 함수 만 간단하게 호출 하면 비동기 작업 을 실현 할 수 있 고 추가 적 인 조작 이 필요 한 것 이 아니다.이 때 우 리 는 우리 의 react-redux 를 위해 중간 부품 을 만들어 서 이 효 과 를 실현 해 야 한다.
    5.1 준비 작업
    액 션 생 성 함수 추가
      그 전에 우리 의 모든 acton 생 성 함 수 는 하나의 action 대상 에 게 직접 돌아 갑 니 다.다음은 서로 다른 action 생 성 함 수 를 쓰 겠 습 니 다.이것 은 하나의 action 대상 이 아니 라 하나의 함수 로 돌아 갑 니 다.그리고 이 함 수 는 두 개의 매개 변수 dispatch 와 getState 를 받 습 니 다.이 함수 내부 에서 우 리 는 해당 하 는 비동기 작업 을 합 니 다.예 를 들 어 age 값 을 수정 합 니 다.
    
    // actionCreate.js
    export const asyncChangeAge = () => {
     //     
     return (dispatch, getState) => {
     setTimeout(v=>{
      console.log('==>', getState());
      dispatch({type: 'AGE_GROW'});
     }, 1000);
     }
    }
    페이지 수정:버튼 을 추가 하고 이벤트 에 연결 하 며 asyncChangeAge 함 수 를 호출 합 니 다.
    
    // Demo.jsx
    // Demo.jsx
    import React from 'react';
    import './style.css';
    //    asyncChangeAge
    import { changeAge, changeUser, asyncChangeAge } from './actionCreate';
    import { connect } from './react-redux';
    
    const mapStateToProps = (state) => {
     return {user: state.user, age: state.age};
    }
    
    //    asyncChangeAge
    @connect(mapStateToProps, {changeAge, changeUser, asyncChangeAge})
    export default class Demo extends React.Component{
     onChange = (e) => {
     this.props.changeUser(e.target.value);
     }
     onClick = () => {
      this.props.changeAge();
     }
     //     
     onClickAsync = () => {
     this.props.asyncChangeAge();
     }
     render(){
     return (
      <div>
      <p>user: {this.props.user}, age: {this.props.age}</p>
      user: 
      <input type="text" className="input" onChange={this.onChange}/>
      &nbsp;
      <button className="btn" onClick={this.onClick}>    </button>
      {/*      */}
      <button className="btn" onClick={this.onClickAsync}>
           
      </button>
      </div>
     );
     }
    }
    페이지 의 변 화 는 사실 매우 간단 하 다.바로 버튼 을 추가 한 것 이다.

    5.2 수요 실현
    그 다음 에 우 리 는 아무것도 고려 하지 않 고 먼저 우리 의 요 구 를 실현 합 니 다.현재 action 생 성 함수 asyncChangeAge 는 대상 으로 돌아 갑 니 다.type 값 은 undefined 이기 때문에 단 추 를 눌 렀 을 때 reducer 는 기본 상황 까지 일치 합 니 다.돌아 오 는 것 은 현재 상태 입 니 다.그 다음 에 우리 의 action 생 성 함수 asyncChangeAge 가 유효 합 니 다.비동기 수정 상태의 역할 달성 하기;
    확장 createStore
    asyncChangeAge 가 돌아 오 는 것 은 더 이상 action 대상 이 아니 라 함수 입 니 다.그러면 사실 우리 가 해 야 할 일 은 매우 간단 하 다.우 리 는 createStore 의 반환 값 dispatch 에 대해 간단 한 확장 만 하면 된다.dispatch 의 action 매개 변수 가 함수 인지 판단 하여 다른 작업 을 진행 합 니 다.
    
    // redux.js
    export const createStore = (reducer) => {
     ......
     //  createStore        dispatch      
     const dispatchExtend = (action) => {
     if(typeof action === 'function'){
      // action    ,    
      action(dispatch, getState);
     } else {
      // action     (  )  dispatch
      dispatch(action);
     }
     }
     return {getState, dispatch: dispatchExtend, subscribe};
    }
    5.3 분리 패키지
    위 에서 저 희 는 createStore 의 반환 값 dispatch 를 확장 하여 redux-react 의 비동기 작업 을 실 현 했 습 니 다.문 제 는 우리 가 코드 를 createStore 에 썼 다 는 것 입 니 다.redux-react 의 비동기 작업 은 필수 옵션 이 아니 라 옵션 이 어야 합 니 다.
    createStore 다시 확장:
    매개 변수 middleware(함수)를 추가 하여 함수 createStore 시작 위치 에서 middleware 가 존재 하 는 지 판단 하고 존재 하면 실행 합 니 다.
    
    // redux.js
    export const createStore = (reducer, middleware) => {
     //    middleware     ,     
     if(middleware){
     return middleware(createStore)(reducer);
     }
    
     let state;
     const listeners = [];
    
     const getState = () => {
     return state;
     }
    
     const dispatch = (action) => {
     state = reducer(state, action);
     listeners.forEach(v => v());
     }
    
     const subscribe = (listener) => {
     listeners.push(listener);
     }
    
     dispatch({type: '%$&HJKAJJHDJHJ'});
    
     return {getState, dispatch, subscribe};
    }
    함수 apply Middleware 를 작성 하여 store 를 만 들 때 createStore 두 번 째 인자 로 합 니 다.
    
    // App.js
    const applyMiddleware = (createStore) => (redux)=> {
     //         store
     const store = createStore(redux);
     //   store
     return {...store}
    }
    
    const store = createStore(reducer, applyMiddleware);
    apply Middleware 함수 내 dispatch 확장
    위의 애플 리 케 이 션 Middleware 함 수 는 아무것도 하지 않 았 습 니 다.createStore 함수 밖 에 함 수 를 끼 웠 습 니 다.그러면 다음 에 우 리 는 올 바른 일 을 해서 dispatch 를 확장 하 겠 습 니 다.
    
    // App.js
    const applyMiddleware = (createStore) => (redux)=> {
     const store = createStore(redux);
    
     const midApi = {
     getState: store.getState,
     dispatch: (...args) => {dispatch(...args);}
     };
    
     const dispatch = (action) => {
     if( typeof action === 'function' ){
      action(midApi.dispatch, midApi.getState);
     } else {
      store.dispatch(action);
     }
     }
    
     return {
     ...store,
     dispatch
     };
    }
    5.4 확장 분리
    위의 글 은 우리 가 원 하 는 효 과 를 실현 하 였 습 니 다.우 리 는 apply Middleware 에서 dispatch 를 확장 하 였 습 니 다.하지만 우 리 는 그렇게 쉽게 만족 할 수 있 잖 아,물론 아니 야!!apply Middleware 에서 dispatch 에 대한 확장 은 따로 꺼 내 서 함수 로 포장 할 수 있 습 니 다.
    애플 리 케 이 션 미 들 웨 어 를 다시 쓰 고 애플 리 케 이 션 미 들 웨 어 에 함 수 를 감 싸 줍 니 다.dispatch 의 확장 을 분리 하고 패키지 하 는 방법 입 니 다.
    
    // App.js
    const applyMiddleware = (middleware) => (createStore) => (redux)=> {
     const store = createStore(redux);
    
     const midApi = {
     getState: store.getState,
     dispatch: (...args) => {dispatch(...args);}
     };
    
     const dispatch = middleware(midApi)(store.dispatch);
    
     return {
     ...store,
     dispatch
     };
    }
    thunk 중간물:사실 thunk 이 야 말로 진정한 중간물 이다.apply Middleware 는 미들웨어 를 연결 하 는 데 만 사 용 됩 니 다.
    
    // App.js 
    const thunk = ({dispatch, getState}) => next => (action) => {
     if(typeof action === 'function'){
     action(dispatch, getState);
     } else {
     next(action);
     }
    }; 
    createStore 를 호출 할 때 중간 부품 thunk 바 인 딩
    
    // App.jsx
    const store = createStore(reducer, applyMiddleware(thunk));
    5.5 코드 정리
    이 단 계 는 apply Middleware 함 수 를 redux.js 파일 로 옮 기 는 것 입 니 다.동시에 thunk 함 수 를 파일 thunk.jsx 에 쓴 다음 App.js 에서 apply Middleware 와 thunk 를 참조 합 니 다.
    최종 효 과 를 보 세 요.

    이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기