>웹 프론트엔드 >JS 튜토리얼 >반응 미들웨어란 무엇입니까?

반응 미들웨어란 무엇입니까?

青灯夜游
青灯夜游원래의
2020-11-26 17:16:015422검색

리액트에서 미들웨어는 store.dispatch 메소드가 수정되었습니다. Action을 발행하고 Reducer를 실행하는 두 단계 사이에 다른 기능이 추가되었습니다. 모듈.

반응 미들웨어란 무엇입니까?

1. 미들웨어의 개념

미들웨어를 이해하기 위해 프레임워크 작성자의 입장에서 문제를 생각해 보겠습니다. 기능을 추가하려면 어디에 추가할 건가요?

(1) 리듀서(Reducer): 상태를 계산하는 기능만 수행하는 순수 함수. 이론적으로 순수 함수는 읽기 및 쓰기 작업을 수행할 수 없기 때문에 다른 함수에는 적합하지 않으며 수행할 수 없습니다.

(2) View: State에 일대일로 대응하며 State의 시각적 레이어로 간주할 수 있으며 다른 기능에는 적합하지 않습니다.

(3) 동작: 데이터를 저장하는 개체, 즉 메시지 전달자는 다른 사람에 의해서만 작동될 수 있으며 자체적으로는 어떤 작업도 수행할 수 없습니다.

고민 끝에 Action을 보내는 단계, 즉 store.dispatch() 메소드만 추가하면 기능을 추가할 수 있습니다. 예를 들어, 로깅 기능을 추가하고 Action, State를 출력하려면 store.dispatch를 다음과 같이 수정하면 됩니다.

let next = store.dispatch;
store.dispatch = function dispatchAndLog(action) {
  console.log('dispatching', action);
  next(action);
  console.log('next state', store.getState());
}

위 코드에서는 store.dispatch를 재정의하고 Action 전송 전후에 인쇄 기능을 추가했습니다. 이것이 미들웨어의 프로토타입이다.

미들웨어는 Action을 발행하고 Reducer를 실행하는 두 단계 사이에 store.dispatch 메소드를 수정하고 다른 기능을 추가하는 기능입니다. 일반적으로 사용되는 미들웨어는 기성품이므로 다른 사람이 작성한 모듈을 참조하면 됩니다.

2. 미들웨어 사용법

자주 사용하는 미들웨어는 기성품이고, 다른 사람이 작성한 모듈만 참고하면 되므로 미들웨어 작성법은 본 튜토리얼에서 다루지 않습니다. 예를 들어, 이전 섹션의 로그 미들웨어에는 미리 만들어진 redux-logger 모듈이 있습니다. 여기서는 미들웨어 사용법만 소개합니다.

import { applyMiddleware, createStore } from 'redux';
import createLogger from 'redux-logger';
const logger = createLogger();
 
const store = createStore(
  reducer,
  applyMiddleware(logger)
);

위 코드에서 redux-logger는 로그 미들웨어 로거를 생성할 수 있는 createLogger 생성기를 제공합니다. 그런 다음 이를 applyMiddleware 메소드에 넣고 createStore 메소드에 전달하여 store.dispatch()의 기능 향상을 완료합니다.

여기서 주목해야 할 두 가지 사항이 있습니다:

(1) createStore 메소드는 전체 애플리케이션의 초기 상태를 매개변수로 받아들일 수 있습니다. 이 경우 applyMiddleware가 세 번째 매개변수가 됩니다.

const store = createStore(
  reducer,
  initial_state,
  applyMiddleware(logger)
);

(2) 미들웨어의 순서가 중요합니다.

const store = createStore(
  reducer,
  applyMiddleware(thunk, promise, logger)
);

위 코드에서 applyMiddleware 메소드의 3개 매개변수는 3개의 미들웨어입니다. 일부 미들웨어에는 주문 요구 사항이 있으므로 사용하기 전에 설명서를 확인하세요. 예를 들어 로거는 끝에 배치해야 합니다. 그렇지 않으면 출력 결과가 올바르지 않게 됩니다.

3.applyMiddlewares()

이것을 보면 ApplyMiddlewares 메소드가 정확히 무엇을 하는지 궁금하실 것입니다.

Redux의 기본 방식으로 모든 미들웨어의 배열을 구성하고 이를 순차적으로 실행하는 기능입니다. 아래는 해당 소스 코드입니다.

export default function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, preloadedState, enhancer) => {
    var store = createStore(reducer, preloadedState, enhancer);
    var dispatch = store.dispatch;
    var chain = [];
 
    var middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    };
    chain = middlewares.map(middleware => middleware(middlewareAPI));
    dispatch = compose(...chain)(store.dispatch);
 
    return {...store, dispatch}
  }
}

위 코드에서 모든 미들웨어는 배열 체인에 배치된 후 중첩되어 실행되고 마지막으로 store.dispatch가 실행됩니다. 보시다시피, 미들웨어(middlewareAPI) 내에서 getState와 dispatch 두 가지 메소드를 사용할 수 있습니다.

4. 비동기 작업의 기본 개념

미들웨어를 이해한 후에는 비동기 작업을 처리할 수 있습니다.

동기 작업은 하나의 작업만 실행하면 됩니다. 비동기 작업의 차이점은 세 개의 작업을 실행해야 한다는 것입니다.

  • 작업이 시작될 때의 작업

  • 작업이 성공할 때의 작업

  • 작업이 실패할 때의 작업

서버에서 데이터를 가져오는 것을 예로 들어보겠습니다. 세 가지 작업을 두 가지로 작성할 수 있습니다. 다른 방법.

// 写法一:名称相同,参数不同
{ type: 'FETCH_POSTS' }
{ type: 'FETCH_POSTS', status: 'error', error: 'Oops' }
{ type: 'FETCH_POSTS', status: 'success', response: { ... } }
// 写法二:名称不同
{ type: 'FETCH_POSTS_REQUEST' }
{ type: 'FETCH_POSTS_FAILURE', error: 'Oops' }
{ type: 'FETCH_POSTS_SUCCESS', response: { ... } }

다양한 유형의 작업 외에도 비동기 작업의 상태도 다양한 작업 상태를 반영하도록 수정해야 합니다. 아래는 State의 예입니다.

let state = {
  // ... 
  isFetching: true,
  didInvalidate: true,
  lastUpdated: 'xxxxxxx'
};

위 코드에서 isFetching of State 속성은 데이터를 가져오는 중인지 여부를 나타냅니다. didInvalidate는 데이터가 오래된 것인지 여부를 나타내고, lastUpdated는 마지막 업데이트 시간을 나타냅니다.

이제 전체 비동기 작업에 대한 아이디어가 매우 명확해졌습니다.

  • 작업이 시작되면 액션을 보내고 트리거 상태는 "작업 진행 중" 상태로 업데이트되며 뷰는 다시 렌더링됩니다.

  • 작업이 완료된 후 다른 액션이 전송됩니다. 트리거 상태는 "작업 종료됨" 상태로 업데이트되고 뷰는 다시 렌더링됩니다. 사용자가 첫 번째 작업을 트리거합니다. 이는 동기 작업과 동일합니다. 작업이 끝나면 시스템이 자동으로 두 번째 작업을 보내는 방법은 무엇입니까?

  • 비결은 Action Creator에 있습니다.
class AsyncApp extends Component {
  componentDidMount() {
    const { dispatch, selectedPost } = this.props
    dispatch(fetchPosts(selectedPost))
  }
// ...

위 코드는 비동기 구성 요소의 예입니다. 성공적으로 로드된 후(comComponentDidMount 메소드) 서버에서 데이터 fetchPosts(selectedSubreddit)를 요청하는 Action을 전송(디스패치 메소드)합니다. 여기서 fetchPosts는 Action Creator입니다. 다음은 fetchPosts의 코드인데, 핵심은 여기에 있습니다.

const fetchPosts = postTitle => (dispatch, getState) => {
  dispatch(requestPosts(postTitle));
  return fetch(`/some/API/${postTitle}.json`)
    .then(response => response.json())
    .then(json => dispatch(receivePosts(postTitle, json)));
  };
};
// 使用方法一
store.dispatch(fetchPosts('reactjs'));
// 使用方法二
store.dispatch(fetchPosts('reactjs')).then(() =>
  console.log(store.getState())
);

上面代码中,fetchPosts是一个Action Creator(动作生成器),返回一个函数。这个函数执行后,先发出一个Action(requestPosts(postTitle)),然后进行异步操作。拿到结果后,先将结果转成 JSON 格式,然后再发出一个 Action( receivePosts(postTitle, json))。

上面代码中,有几个地方需要注意。

(1)fetchPosts返回了一个函数,而普通的 Action Creator 默认返回一个对象。

(2)返回的函数的参数是dispatch和getState这两个 Redux 方法,普通的 Action Creator 的参数是 Action 的内容。

(3)在返回的函数之中,先发出一个 Action(requestPosts(postTitle)),表示操作开始。

(4)异步操作结束之后,再发出一个 Action(receivePosts(postTitle, json)),表示操作结束。

这样的处理,就解决了自动发送第二个 Action 的问题。但是,又带来了一个新的问题,Action 是由store.dispatch方法发送的。而store.dispatch方法正常情况下,参数只能是对象,不能是函数。

这时,就要使用中间件redux-thunk。

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducers';
// Note: this API requires redux@>=3.1.0
const store = createStore(
  reducer,
  applyMiddleware(thunk)
);

上面代码使用redux-thunk中间件,改造store.dispatch,使得后者可以接受函数作为参数。

因此,异步操作的第一种解决方案就是,写出一个返回函数的 Action Creator,然后使用redux-thunk中间件改造store.dispatch。

六、redux-promise 中间件

既然 Action Creator 可以返回函数,当然也可以返回其他值。另一种异步操作的解决方案,就是让 Action Creator 返回一个 Promise 对象。

这就需要使用redux-promise中间件。

import { createStore, applyMiddleware } from 'redux';
import promiseMiddleware from 'redux-promise';
import reducer from './reducers';
 
const store = createStore(
  reducer,
  applyMiddleware(promiseMiddleware)
);

这个中间件使得store.dispatch方法可以接受 Promise 对象作为参数。这时,Action Creator 有两种写法。写法一,返回值是一个 Promise 对象。

const fetchPosts = 
  (dispatch, postTitle) => new Promise(function (resolve, reject) {
     dispatch(requestPosts(postTitle));
     return fetch(`/some/API/${postTitle}.json`)
       .then(response => {
         type: 'FETCH_POSTS',
         payload: response.json()
       });
});

写法二,Action 对象的payload属性是一个 Promise 对象。这需要从redux-actions模块引入createAction方法,并且写法也要变成下面这样。

import { createAction } from 'redux-actions';
 
class AsyncApp extends Component {
  componentDidMount() {
    const { dispatch, selectedPost } = this.props
    // 发出同步 Action
    dispatch(requestPosts(selectedPost));
    // 发出异步 Action
    dispatch(createAction(
      'FETCH_POSTS', 
      fetch(`/some/API/${postTitle}.json`)
        .then(response => response.json())
    ));
  }

上面代码中,第二个dispatch方法发出的是异步 Action,只有等到操作结束,这个 Action 才会实际发出。注意,createAction的第二个参数必须是一个 Promise 对象。

看一下redux-promise的源码,就会明白它内部是怎么操作的。

export default function promiseMiddleware({ dispatch }) {
  return next => action => {
    if (!isFSA(action)) {
      return isPromise(action)
        ? action.then(dispatch)
        : next(action);
    }
 
    return isPromise(action.payload)
      ? action.payload.then(
          result => dispatch({ ...action, payload: result }),
          error => {
            dispatch({ ...action, payload: error, error: true });
            return Promise.reject(error);
          }
        )
      : next(action);
  };
}

从上面代码可以看出,如果 Action 本身是一个 Promise,它 resolve 以后的值应该是一个 Action 对象,会被dispatch方法送出(action.then(dispatch)),但 reject 以后不会有任何动作;如果 Action 对象的payload属性是一个 Promise 对象,那么无论 resolve 和 reject,dispatch方法都会发出 Action。

위 내용은 반응 미들웨어란 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.