API(api/locales)からすべてのロケールを選択したいとします。sagaでカスタムrestClientを使用する
私の問題は、yieldコール()が関数を計画文字列(yes yes plain string)として返すということです。私はその理由を知りません!
多分私はyield + call + restClientの応答で何かを見逃しましたか?このような= \
マイ佐賀ファイルを見て:
import types from './types';
import actions from './actions';
import { call, put, takeEvery } from 'redux-saga/effects';
import restClient from './../../restClient';
function* getLocalesSaga() {
try {
yield put({type: types.GET_LOCALES_LOADING});
let locales;
locales = yield call(restClient, 'GET', 'locales');
console.log(locales); // this show the function string!!!
if (!locales.data) {
throw new Error('REST response must contain a data key');
}
yield put({type: types.LOCALES_RECEIVED, locales })
} catch (error) {
console.log(error);
yield put({type: types.GET_LOCALES_FAILURE, error})
}
}
export default function* localesSaga() {
yield [
takeEvery(types.GET_LOCALES, getLocalesSaga),
takeEvery(types.GET_LOCALES_LOADING, actions.loadingLocales),
takeEvery(types.LOCALES_RECEIVED, actions.localesReceived),
takeEvery(types.GET_LOCALES_FAILURE, actions.failedLocales),
];
}
にconsole.log出力は次のようになります。
ƒ (type, resource, params) {
if (type === __WEBPACK_IMPORTED_MODULE_0_admin_on_rest__["GET_MANY"]) {
return Promise.all(params.ids.map(function (id) {
return httpClient(apiUrl + '/' +…
ブラウザネットワーク]タブには、要求がありません。 console.logとは別にコンソールにJSエラーがありません。
管理者コンポーネントにcustomSagas = {customsSagas}を設定してサガを登録しました。
私はfetch()関数を使用すると機能します。
私は、認証トークンと要求と応答のすべてのロジックを含むrestClientを使用したいと思います。 restClientは、カスタムであり、これはコードです:
import {
GET_LIST,
GET_ONE,
GET_MANY,
GET_MANY_REFERENCE,
CREATE,
UPDATE,
DELETE,
fetchUtils
} from 'admin-on-rest';
const { queryParameters, fetchJson } = fetchUtils;
const apiUrl = process.env.REACT_APP_API_PATH;
const httpClient = (url, options = {}) => {
if (!options.headers) {
options.headers = new Headers({ Accept: 'application/json' });
}
const token = localStorage.getItem('token');
options.headers.set('Authorization', `Bearer ${token}`);
return fetchJson(url, options);
}
/**
* Maps admin-on-rest queries to a json-server powered REST API
*
* @see https://github.com/typicode/json-server
* @example
* GET_LIST => GET http://my.api.url/posts?_sort=title&_order=ASC&_start=0&_end=24
* GET_ONE => GET http://my.api.url/posts/123
* GET_MANY => GET http://my.api.url/posts/123, GET http://my.api.url/posts/456, GET http://my.api.url/posts/789
* UPDATE => PUT http://my.api.url/posts/123
* CREATE => POST http://my.api.url/posts/123
* DELETE => DELETE http://my.api.url/posts/123
*/
export default() => {
/**
* @param {String} type One of the constants appearing at the top if this file, e.g. 'UPDATE'
* @param {String} resource Name of the resource to fetch, e.g. 'posts'
* @param {Object} params The REST request params, depending on the type
* @returns {Object} { url, options } The HTTP request parameters
*/
const convertRESTRequestToHTTP = (type, resource, params) => {
let url = '';
const options = {};
switch (type) {
case GET_LIST: {
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const query = {
...params.filter,
sort: field,
order: order,
page: page,
per_page: perPage,
};
url = `${apiUrl}/${resource}?${queryParameters(query)}`;
break;
}
case GET_ONE:
url = `${apiUrl}/${resource}/${params.id}`;
break;
case GET_MANY_REFERENCE: {
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const query = {
...params.filter,
[params.target]: params.id,
_sort: field,
_order: order,
_start: (page - 1) * perPage,
_end: page * perPage,
};
url = `${apiUrl}/${resource}?${queryParameters(query)}`;
break;
}
case UPDATE:
url = `${apiUrl}/${resource}/${params.id}`;
options.method = 'PUT';
options.body = JSON.stringify(params.data);
break;
case CREATE:
url = `${apiUrl}/${resource}`;
options.method = 'POST';
options.body = JSON.stringify(params.data);
break;
case DELETE:
url = `${apiUrl}/${resource}/${params.id}`;
options.method = 'DELETE';
break;
default:
throw new Error(`Unsupported fetch action type ${type}`);
}
return { url, options };
};
/**
* @param {Object} response HTTP response from fetch()
* @param {String} type One of the constants appearing at the top if this file, e.g. 'UPDATE'
* @param {String} resource Name of the resource to fetch, e.g. 'posts'
* @param {Object} params The REST request params, depending on the type
* @returns {Object} REST response
*/
const convertHTTPResponseToREST = (response, type, resource, params) => {
const { headers, json } = response;
switch (type) {
case GET_LIST:
case GET_MANY_REFERENCE:
if (!headers.has('x-total-count')) {
throw new Error('The X-Total-Count header is missing in the HTTP Response. The jsonServer REST client expects responses for lists of resources to contain this header with the total number of results to build the pagination. If you are using CORS, did you declare X-Total-Count in the Access-Control-Expose-Headers header?');
}
return {
// change the primary key to uuid
data: json.data.map(resource => resource = { ...resource, id: resource.uuid }),
total: parseInt(headers.get('x-total-count').split('/').pop(), 10),
};
case UPDATE:
case DELETE:
case GET_ONE:
return { data: json, id: json.uuid };
case CREATE:
return { data: { ...params.data, id: json.uuid } };
default:
return { data: json };
}
};
/**
* @param {string} type Request type, e.g GET_LIST
* @param {string} resource Resource name, e.g. "posts"
* @param {Object} payload Request parameters. Depends on the request type
* @returns {Promise} the Promise for a REST response
*/
return (type, resource, params) => {
if (type === GET_MANY) {
return Promise.all(params.ids.map(id => httpClient(`${apiUrl}/${resource}/${id}`)))
.then(responses => ({ data: responses.map(response => response.json) }));
}
const { url, options } = convertRESTRequestToHTTP(type, resource, params);
return httpClient(url, options)
.then(response => convertHTTPResponseToREST(response, type, resource, params));
};
};
ここに役立つとrestClient代わりにJSONを返す文字列として返され、なぜ私に言うことができる任意の1?
GET_LISTでもGET_ONEでもありません。これは単なる通常のGETリクエストです。 私はGET_ONEとGET_LISTを使用しようとしましたが、まだ応答は普通の文字列として取得されています。
編集&ソリューション:
おかげで、GET要求の代わりにrestClientのフェッチを使用することが明確である@Gildasします。 restClientは<resource />
のためだけに使用されており、ドキュメントではあまり明確ではありません。 さらに、私のメインのサガ機能でput
を使用すると、アクション作成者は役に立たなかった。
は、このようなルックスをフェッチマイ、それが動作します:
function getLocales() {
return fetch(process.env.REACT_APP_API_PATH + '/locales', { method: 'GET' })
.then(response => (
Promise.resolve(response)
))
.then(response => (
response.json()
))
.catch((e) => {
console.error(e);
});
}
私はこのようにそれを呼び出した場合:
const { languages, currentLocale } = yield call(getLocales);
は、高度にありがとうございます。 レオ。
私はactions.localesReceived'と 'actions.failedLocales'は、アクションクリエイターです'、 'actions.loadingLocales'を想定しますか?なぜあなたは 'getLocalesSaga'のようなサガのように使っていますか? – Gildas
Hiii Gildas!コメントありがとう!私はダックのスタイルを使用しています:https://medium.freecodecamp.org/scaling-your-redux-app-with-ducks-6115955638be私は行動があり、私はそれらを使用していますoperations.jsファイルにはすべてのサガ...多分私は何かを見逃して、あなたはより良いアクション作成方法論をお勧めできますか? – llioor
いいえ、私が意味することは、あなたがアクションクリエイターを、最後の3回のtakeEveryでサゲーのように渡しているということです。私が知る限り、これはうまくいかなかった – Gildas