2017-12-07 1 views
0

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); 

は、高度にありがとうございます。 レオ。

+0

私はactions.localesReceived'と 'actions.failedLocales'は、アクションクリエイターです'、 'actions.loadingLocales'を想定しますか?なぜあなたは 'getLocalesSaga'のようなサガのように使っていますか? – Gildas

+0

Hiii Gildas!コメントありがとう!私はダックのスタイルを使用しています:https://medium.freecodecamp.org/scaling-your-redux-app-with-ducks-6115955638be私は行動があり、私はそれらを使用していますoperations.jsファイルにはすべてのサガ...多分私は何かを見逃して、あなたはより良いアクション作成方法論をお勧めできますか? – llioor

+0

いいえ、私が意味することは、あなたがアクションクリエイターを、最後の3回のtakeEveryでサゲーのように渡しているということです。私が知る限り、これはうまくいかなかった – Gildas

答えて

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), 
    ]; 
} 

はまた、restClientfetchではありません。 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); 
} 
+0

ありがとう、私の友人!正しいとマークされ、投票されました! – llioor

+0

簡単な質問、コンポーネントを作成するApp.jsファイルから "getLocalesSaga"をどのように起動できますか?今度はコンポーネントを読み込み、componentWillMount関数でGET_LOCALESアクション作成者を起動します。ありがとう – llioor

+0

管理コンポーネントに渡すメッセージを読み込もうとしている場合は動作しません。 Adminコンポーネントが新しい小道具で再レンダリングすると、店舗に関するエラーが発生します。メッセージの動的ロードは現在サポートされていません。 [documentation](https://marmelab.com/admin-on-rest/Translation.html#changing-locale-at-runtime) – Gildas

関連する問題