我想从我的API(api / locales)中选择所有语言环境。
我的问题是yield call()将函数作为计划字符串返回(是的是纯字符串),我不知道为什么!
也许我错过了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错误。
我在Admin组件上使用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?
它不是GET_LIST,也不是GET_ONE请求。这只是一个普通的GET请求。 我试图使用GET_ONE和GET_LIST,但我仍然得到响应为函数plain string。
编辑&溶液
感谢@Gildas,对于GET请求,使用fetch而不是restClient更清楚。 restClient仅用于<resource />
,文档不太清楚。
而且,当我在我的主要传奇函数中使用put
时,动作创建者是无用的。
我的fetch看起来像这样,它可以工作:
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);
先谢谢你。 利奥。
答案 0 :(得分:1)
这一部分真的很奇怪,虽然你在getLocalesSaga中做put
它们,但你似乎是有约束力的动作创造者,好像它们是传奇的一样:
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),
];
}
此外,restClient
不是fetch
。 GET
不是其识别的类型(请参阅documentation)。您不应该将restClient
用于任何不属于管理员休息条件的资源。在这里,您确实应该使用fetch
。
这应该改写如下:
import types from './types';
import actions from './actions';
import { call, put, takeEvery } from 'redux-saga/effects';
import restClient from './../../restClient';
function fetchLocales() {
return fetch(...);
}
function* getLocalesSaga() {
try {
yield put(actions.loadingLocales());
let locales;
locales = yield call(fetchLocales);
console.log(locales); // this show the function string!!!
if (!locales.data) {
throw new Error('REST response must contain a data key');
}
yield put(actions.localesReceived(locales))
} catch (error) {
console.log(error);
yield put(actions.failedLocales(error))
}
}
export default function* localesSaga() {
yield takeEvery(types.GET_LOCALES, getLocalesSaga);
}