応答テクノロジー(冗長ミドルウェアによる非同期タスクの管理)-1
Webアプリケーションに応答してAPIサーバをバインドする場合は、APIリクエストのステータスも管理する必要があります.
要求開始時:ロード中
要求が成功または失敗した場合:ロードが完了したことを示します.
成功した場合:管理サーバが受信した応答のステータス
失敗した場合:管理サーバが返すエラーのステータス
応答プロジェクトでreduceが使用され、これらの非同期操作を管理する必要がある場合は、「ミドルウェア」を使用して、非常に効率的で便利なステータス管理を行うことができます.
この章では、Ridexミドルウェアの概念を理解し、非同期タスクを処理する方法を学習します.
実習プロセス.作業環境準備 直接作成ミドルウェア Redux-Logger を使用ミドルウェアを使用して非同期タスク を管理
18-1. 作業環境の準備
動作→ミドルウェア→リカバリプログラム→ショップ ミドルウェアは、Reduserが動作を処理する前に実行できる動作が送信動作は、コンソールにのみ が書き込まれる.で受信動作情報に基づいて、動作 をキャンセルする.他のタイプの動作プログラム を追加する.
実際のプロジェクト作業では,直接中路ソフトウェアを作成して使用する作業は多くない.他の開発者が作成したミドルウェアを使えばいいのですが、これは初めてなので理解が必要なので、自分で作成してどのように働いているのか理解してみましょう.
レコードミドルウェアを作成し、デバッグ動作のたびにコンソールに動作の情報と動作デバッグ前後の状態を表示します.
src/lib/loggerMiddleware.js
その2つとは異なり、nextはよく知られておらず、nextパラメータは関数形式、storeである.ディスパッチと似たような役割を果たしているそうです.違いは、next(action)が呼び出されると、次の処理が必要なミドルウェアに動作が伝達され、次のミドルウェアがなければReduserに動作が伝達されることである.
ミドルウェア内部store.dispatchを使用して、最初のミドルウェアから再処理を開始します.ミドルウェアにnextが使用されていない場合、アクションは再生プログラムに渡されません.(無視アクション)
今回のミドルウェアは、コンソールに情報を順次表示します.移行ステータス 動作情報 新状態
index.js
オープンソースコミュニティのredux-loggerミドルウェアをインストールして使用します.先ほど作成したloggerMiddlewareよりも良いライブラリで、ブラウザコンソールのフォーマットも簡潔だそうです.
18-3. ミドルウェアを使用した非同期タスクの処理
GET https://jsonplaceholder.typicode.com/posts/:id GET https://jsonplaceholder.typicode.com/users APIを呼び出す場合、PromiseベースのWebクライアントaxiosが一般的に使用されます.
lib/api.js
modules/sample.js
翻訳機は既に完成しており、この翻訳機を翻訳機に含める.
modules/index.js
components/Sample.js
たとえば、post&&&はpostオブジェクトが有効な場合にのみ内部postを使用します.見出しbody値が表示されます.データがなければpost.titleをクエリーしようとするとjavascriptエラーが発生し、検証する必要があります.
ユーザも同様にデータが配列形式で入ることを期待し,map関数を用いる.
ただし、有効性チェックを行わないとnull値に対してmap関数が呼び出され、最終的にmap関数が存在しないためエラーが発生します.
要求開始時:ロード中
要求が成功または失敗した場合:ロードが完了したことを示します.
成功した場合:管理サーバが受信した応答のステータス
失敗した場合:管理サーバが返すエラーのステータス
応答プロジェクトでreduceが使用され、これらの非同期操作を管理する必要がある場合は、「ミドルウェア」を使用して、非常に効率的で便利なステータス管理を行うことができます.
この章では、Ridexミドルウェアの概念を理解し、非同期タスクを処理する方法を学習します.
実習プロセス.
18-1. 作業環境の準備 yarn create react-app learn-redux-middleware
cd learn-redux-middleware
yarn add redux react-redux redux-actions
Ridex用のコードの準備
まず、反放射モジュールを作成します.
modules/counter.jsimport { createAction, handleActions } from "redux-actions";
const INCREASE = "counter/INCREASE";
const DECREASE = "counter/DECREASE";
export const increase = createAction(INCREASE);
export const decrease = createAction(DECREASE);
const initialState = 0; // 상태는 꼭 객체일 필요가 없다. 숫자도 작동
const counter = handleActions(
{
[INCREASE]: (state) => state + 1,
[DECREASE]: (state) => state - 1,
},
initialState
);
export default counter;
スーパーユーザーの作成
modules/index.jsimport { combineReducers } from "redux";
import counter from "./counter";
const rootReducer = combineReducers({ counter });
export default rootReducer;
srcディレクトリのインデックス.jsにショップを作成し、プロバイダアプリケーションに応答プロジェクトにコピーします.import React from "react";
import ReactDOM from "react-dom";
import { createStore } from "redux";
import { Provider } from "react-redux";
import "./index.css";
import App from "./App";
import rootReducer from "./modules";
const store = createStore(rootReducer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
カウンタ構成部品とカウンタコンテナ構成部品の作成
components/Counter.js(Presentation素子)import React from "react";
const Counter = ({ onIncrease, onDecrease, number }) => {
return (
<div>
<h1>{number}</h1>
<button onClick={onIncrease}>+1</button>
<button onClick={onDecrease}>-1</button>
</div>
);
};
export default Counter;
containers/CounterContainer.js(容量素子)import React from "react";
import { connect } from "react-redux";
import { increase, decrease } from "../modules/counter";
import Counter from "../components/Counter";
const CounterContainer = ({ number, increase, decrease }) => {
return (
<Counter number={number} onIncrease={increase} onDecrease={decrease} />
);
};
export default connect(
(state) => ({
number: state.counter,
}),
{
increase,
decrease,
}
)(CounterContainer);
ComputerContainerをAppに表示するimport React from "react";
import CounterContainer from "./containers/CounterContainer";
const App = () => {
return (
<div>
<CounterContainer />
</div>
);
};
export default App;
18-2. ミドルウェアとは?
ミドルウェア:動作(トリガ動作)を派遣する場合、Reducerがその動作を処理する前に予め指定されたタスクを実行します.(ミドルウェアはアクションとヘビー級ボクサーの中間者)
ミドルウェアコース?
yarn create react-app learn-redux-middleware
cd learn-redux-middleware
yarn add redux react-redux redux-actions
import { createAction, handleActions } from "redux-actions";
const INCREASE = "counter/INCREASE";
const DECREASE = "counter/DECREASE";
export const increase = createAction(INCREASE);
export const decrease = createAction(DECREASE);
const initialState = 0; // 상태는 꼭 객체일 필요가 없다. 숫자도 작동
const counter = handleActions(
{
[INCREASE]: (state) => state + 1,
[DECREASE]: (state) => state - 1,
},
initialState
);
export default counter;
import { combineReducers } from "redux";
import counter from "./counter";
const rootReducer = combineReducers({ counter });
export default rootReducer;
import React from "react";
import ReactDOM from "react-dom";
import { createStore } from "redux";
import { Provider } from "react-redux";
import "./index.css";
import App from "./App";
import rootReducer from "./modules";
const store = createStore(rootReducer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
import React from "react";
const Counter = ({ onIncrease, onDecrease, number }) => {
return (
<div>
<h1>{number}</h1>
<button onClick={onIncrease}>+1</button>
<button onClick={onDecrease}>-1</button>
</div>
);
};
export default Counter;
import React from "react";
import { connect } from "react-redux";
import { increase, decrease } from "../modules/counter";
import Counter from "../components/Counter";
const CounterContainer = ({ number, increase, decrease }) => {
return (
<Counter number={number} onIncrease={increase} onDecrease={decrease} />
);
};
export default connect(
(state) => ({
number: state.counter,
}),
{
increase,
decrease,
}
)(CounterContainer);
import React from "react";
import CounterContainer from "./containers/CounterContainer";
const App = () => {
return (
<div>
<CounterContainer />
</div>
);
};
export default App;
ミドルウェア:動作(トリガ動作)を派遣する場合、Reducerがその動作を処理する前に予め指定されたタスクを実行します.(ミドルウェアはアクションとヘビー級ボクサーの中間者)
ミドルウェアコース?
18-2-1. ミドルウェアの作成
実際のプロジェクト作業では,直接中路ソフトウェアを作成して使用する作業は多くない.他の開発者が作成したミドルウェアを使えばいいのですが、これは初めてなので理解が必要なので、自分で作成してどのように働いているのか理解してみましょう.
レコードミドルウェアを作成し、デバッグ動作のたびにコンソールに動作の情報と動作デバッグ前後の状態を表示します.
src/lib/loggerMiddleware.js
const loggerMiddleware = (store) => (next) => (action) => {
// 미들웨어 기본 구조
};
export default loggerMiddleware;
上のコードはRidexミドルウェア構造と呼ばれています.矢印関数をfunctionキーとして展開して書き込むconst loggerMiddleware = function loggerMiddleware (store) {
return function (next) {
return function (action) {
// 미들웨어 기본 구조
}
}
}
ミドルウェアは最終的に戻り関数の関数と呼ばれます.ここで,関数でパラメータとして受信するstoreはリカバリインスタンス,actionは派遣された動作を指す.その2つとは異なり、nextはよく知られておらず、nextパラメータは関数形式、storeである.ディスパッチと似たような役割を果たしているそうです.違いは、next(action)が呼び出されると、次の処理が必要なミドルウェアに動作が伝達され、次のミドルウェアがなければReduserに動作が伝達されることである.
ミドルウェア内部store.dispatchを使用して、最初のミドルウェアから再処理を開始します.ミドルウェアにnextが使用されていない場合、アクションは再生プログラムに渡されません.(無視アクション)
今回のミドルウェアは、コンソールに情報を順次表示します.
const loggerMiddleware = (store) => (next) => (action) => {
console.log(action && action.type); // 액션 타입으로 log를 그룹화
console.log("이전 상태", store.getState());
console.log("액션", action);
next(action); // 다음 미들웨어 혹은 리듀서에게 전달
console.log("다음 상태", store.getState()); // 업데이트된 상태
console.groupEnd(); // 그룹 끝
};
export default loggerMiddleware;
作成した冗長ミドルウェアをショップに適用します.ミドルウェアはショップの作成に適用されますindex.js
import React from "react";
import ReactDOM from "react-dom";
import { createStore, applyMiddleware } from "redux";
import { Provider } from "react-redux";
import "./index.css";
import App from "./App";
import rootReducer from "./modules";
import loggerMiddleware from "./lib/loggerMiddleware";
const store = createStore(rootReducer, applyMiddleware(loggerMiddleware));
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
18-2-2. redux-loggerの使用
オープンソースコミュニティのredux-loggerミドルウェアをインストールして使用します.先ほど作成したloggerMiddlewareよりも良いライブラリで、ブラウザコンソールのフォーマットも簡潔だそうです.
yarn add redux-logger
index.jsimport React from "react";
import ReactDOM from "react-dom";
import { createStore, applyMiddleware } from "redux";
import { Provider } from "react-redux";
import "./index.css";
import App from "./App";
import rootReducer from "./modules";
// import loggerMiddleware from "./lib/loggerMiddleware";
import { createLogger } from "redux-logger";
const logger = createLogger();
const store = createStore(rootReducer, applyMiddleware(logger));
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
18-3. ミドルウェアを使用した非同期タスクの処理
非同期タスクを処理するときに役立つミドルウェアは本当にたくさんあります.本書で紹介するミドルウェア
18-3-1. redux-thunk
Ridexを使用するプロジェクトで非同期操作を処理する際に最も基本的に使用されるミドルウェア
オブジェクトではなく関数形式の動作でdispatchを許可
18-3-1-1. Thunkとは?
Thunkは,特定のタスクを関数として後回しにすることを意味する.
18-3-1-2. アプリケーションミドルウェア
yarn add redux-thunk
ショップの作成時にredux-thunkを適用
index.jsimport React from "react";
import ReactDOM from "react-dom";
import { createStore, applyMiddleware } from "redux";
import { Provider } from "react-redux";
import "./index.css";
import App from "./App";
import rootReducer from "./modules";
// import loggerMiddleware from "./lib/loggerMiddleware";
import { createLogger } from "redux-logger";
import ReduxThunk from "redux-thunk";
const logger = createLogger();
const store = createStore(rootReducer, applyMiddleware(logger, ReduxThunk));
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
18-3-1-3. Thunk生成関数の作成
redux-thunkは、通常のアクションオブジェクトchellではなく、アクション生成関数で関数を返します.
increationsyncとdecreationsync関数を作成し、大きな数値を非同期で変更します.import { createAction, handleActions } from "redux-actions";
const INCREASE = "counter/INCREASE";
const DECREASE = "counter/DECREASE";
export const increase = createAction(INCREASE);
export const decrease = createAction(DECREASE);
// 1초 뒤에 increase 혹은 decrease 함수를 디스패치함
export const increaseAsync = () => (dispatch) => {
setTimeout(() => {
dispatch(increase());
}, 1000);
};
export const decreaseAsync = () => (dispatch) => {
setTimeout(() => {
dispatch(decrease());
}, 1000);
};
const initialState = 0; // 상태는 꼭 객체일 필요가 없다. 숫자도 작동
const counter = handleActions(
{
[INCREASE]: (state) => state + 1,
[DECREASE]: (state) => state - 1,
},
initialState
);
export default counter;
Reduceモジュールを変更すると、ComputerContainerによって呼び出されたアクション作成関数が変更されます.import React from "react";
import { connect } from "react-redux";
import { increaseAsync, decreaseAsync } from "../modules/counter";
import Counter from "../components/Counter";
const CounterContainer = ({ number, increaseAsync, decreaseAsync }) => {
return (
<Counter
number={number}
onIncrease={increaseAsync}
onDecrease={decreaseAsync}
/>
);
};
export default connect(
(state) => ({
number: state.counter,
}),
{
increaseAsync,
decreaseAsync,
}
)(CounterContainer);
18-3-1-4. Webリクエストの非同期処理
thunkのプロパティを使用して、Webリクエストの非同期操作を処理します.
JSOnPlaceholder(https://jsonplaceholder.typicode.com)が提供する偽APIを使用してWebリクエストを練習します.使用するAPIは次のとおりです.
yarn add redux-thunk
import React from "react";
import ReactDOM from "react-dom";
import { createStore, applyMiddleware } from "redux";
import { Provider } from "react-redux";
import "./index.css";
import App from "./App";
import rootReducer from "./modules";
// import loggerMiddleware from "./lib/loggerMiddleware";
import { createLogger } from "redux-logger";
import ReduxThunk from "redux-thunk";
const logger = createLogger();
const store = createStore(rootReducer, applyMiddleware(logger, ReduxThunk));
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
import { createAction, handleActions } from "redux-actions";
const INCREASE = "counter/INCREASE";
const DECREASE = "counter/DECREASE";
export const increase = createAction(INCREASE);
export const decrease = createAction(DECREASE);
// 1초 뒤에 increase 혹은 decrease 함수를 디스패치함
export const increaseAsync = () => (dispatch) => {
setTimeout(() => {
dispatch(increase());
}, 1000);
};
export const decreaseAsync = () => (dispatch) => {
setTimeout(() => {
dispatch(decrease());
}, 1000);
};
const initialState = 0; // 상태는 꼭 객체일 필요가 없다. 숫자도 작동
const counter = handleActions(
{
[INCREASE]: (state) => state + 1,
[DECREASE]: (state) => state - 1,
},
initialState
);
export default counter;
import React from "react";
import { connect } from "react-redux";
import { increaseAsync, decreaseAsync } from "../modules/counter";
import Counter from "../components/Counter";
const CounterContainer = ({ number, increaseAsync, decreaseAsync }) => {
return (
<Counter
number={number}
onIncrease={increaseAsync}
onDecrease={decreaseAsync}
/>
);
};
export default connect(
(state) => ({
number: state.counter,
}),
{
increaseAsync,
decreaseAsync,
}
)(CounterContainer);
記事の読み取り(:idは1~100の数字)
すべてのユーザー情報を読み込み
yarn add axios
APIをすべて関数化します.個々のAPIを呼び出す関数を個別に記述すると,後で使用する際にその毒性とメンテナンスが容易になる.exportを使用してエクスポートし、他のファイルからロードおよび使用します.lib/api.js
import axios from "axios";
export const getPost = (id) =>
axios.get(`https://jsonplaceholder.typicode.com/posts/${id}`);
export const getUsers = (id) =>
axios.get(`https://jsonplaceholder.typicode.com/users`);
上記のAPIを使用して、「サンプル」と呼ばれるレプリケーションを作成し、データを受信してステータスを管理します.modules/sample.js
import { handleActions } from "redux-actions";
import * as api from "../lib/api";
// 액션 타입을 선언
// 한 요청당 세 개를 만들어야 함
const GET_POST = "sample/GET_POST";
const GET_POST_SUCCESS = "sample/GET_POST_SUCCESS";
const GET_POST_FAILURE = "sample/GET_POST_FAILURE";
const GET_USERS = "sample/GET_USERS";
const GET_USERS_SUCCESS = "sample/GET_USERS_SUCCESS";
const GET_USERS_FAILURE = "sample/GET_USERS_FAILURE";
// thunk 함수를 생성
// thunk 함수 내부에서는 시작할 때, 성공했을 때, 실패했을 때 다른 액션을 디스패치한다.
export const getPost = (id) => async (dispatch) => {
dispatch({ type: GET_POST }); // 요청을 시작한 것을 알림
try {
const response = await api.getPost(id);
dispatch({
type: GET_POST_SUCCESS,
payload: response.data,
}); // 요청 성공
} catch (e) {
dispatch({
type: GET_POST_FAILURE,
payload: e,
error: true,
}); // 요청 실패
throw e; // 나중에 컴포넌트단에서 에러를 조회할 수 있도록 해줌
}
};
export const getUsers = () => async (dispatch) => {
dispatch({ type: GET_USERS }); // 요청을 시작한 것을 알림
try {
const response = await api.getUsers();
dispatch({
type: GET_USERS_SUCCESS,
payload: response.data,
}); // 요청 성공
} catch (e) {
dispatch({
type: GET_USERS_FAILURE,
payload: e,
error: true,
}); // 에러발생
throw e; // 나중에 컴포넌트단에서 에러를 조회할 수 있게 해 줌
}
};
// 초기 상태를 선언
// 요청의 로딩 중 상태는 loading이라는 객체에서 관리
const initialState = {
loading: {
GET_POST: false,
GET_USERS: false,
},
post: null,
users: null,
};
const sample = handleActions(
{
[GET_POST]: (state) => ({
...state,
loading: {
...state.loading,
GET_POST: true, // 요청시작
},
}),
[GET_POST_SUCCESS]: (state, action) => ({
...state,
loading: {
...state.loading,
GET_POST: false, // 요청 완료
},
post: action.payload,
}),
[GET_POST_FAILURE]: (state, action) => ({
...state,
loading: {
...state.loading,
GET_POST: false, // 요청 완료
},
}),
[GET_USERS]: (state) => ({
...state,
loading: {
...state.loading,
GET_USERS: true, // 요청 시작
},
}),
[GET_USERS_SUCCESS]: (state, action) => ({
...state,
loading: {
...state.loading,
GET_USERS: false, // 요청 완료
},
users: action.payload,
}),
[GET_USERS_FAILURE]: (state, action) => ({
...state,
loading: {
...state.loading,
GET_USERS: false, // 요청 완료
},
}),
},
initialState
);
export default sample;
コードに繰り返される論理はかなり多い.まず、コンテナ構成部品を使用してデータ要求を正常に処理し、その後、繰り返しの論理を分離して、コードを再使用する形で再パッケージします.翻訳機は既に完成しており、この翻訳機を翻訳機に含める.
modules/index.js
import { combineReducers } from "redux";
import counter from "./counter";
import sample from "./sample";
const rootReducer = combineReducers({ counter, sample });
export default rootReducer;
今回作成するコンポーネントではpostはtitleとbodyのみ、userはユーザー名とemailのみを表示します.components/Sample.js
import React from "react";
const Sample = ({ loadingPost, loadingUsers, post, users }) => {
return (
<div>
<section>
<h1>포스트</h1>
{loadingPost && "로딩중..."}
{!loadingPost && post && (
<div>
<h3>{post.title}</h3>
<h3>{post.body}</h3>
</div>
)}
</section>
<hr />
<section>
<h1>사용자 목록</h1>
{loadingUsers && "로딩 중..."}
{!loadingUsers && users && (
<ul>
{users.map((user) => (
<li key={user.id}>
{user.username} ({user.email})
</li>
))}
</ul>
)}
</section>
</div>
);
};
export default Sample;
データのロードとレンダリングには、有効性チェックが重要です.たとえば、post&&&はpostオブジェクトが有効な場合にのみ内部postを使用します.見出しbody値が表示されます.データがなければpost.titleをクエリーしようとするとjavascriptエラーが発生し、検証する必要があります.
ユーザも同様にデータが配列形式で入ることを期待し,map関数を用いる.
ただし、有効性チェックを行わないとnull値に対してmap関数が呼び出され、最終的にmap関数が存在しないためエラーが発生します.
Reference
この問題について(応答テクノロジー(冗長ミドルウェアによる非同期タスクの管理)-1), 我々は、より多くの情報をここで見つけました https://velog.io/@dohy9443/리액트를-다루는-기술-리덕스-미들웨어를-통한-비동기-작업-관리-1テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol