React学習ノート_realword
一、normalizr扁平化データ
ステータスをフラット化したAPIを維持すると、ネストされたリソースが返されることがよくあります.これはFluxまたはReduxベースのアーキテクチャでは非常に困難に処理されます.normalizrのようなライブラリを用いてデータをフラット化し,状態をできるだけフラット化することを推奨する.
例:
典型的なAPI呼び出しはデータを返す:
{
"id": "123",
"author": {
"id": "1",
"name": "Paul"
},
"title": "My awesome blog post",
"comments": [
{
"id": "324",
"commenter": {
"id": "2",
"name": "Nicole"
}
}
]
}
データをフラット化する方法:
import { normalize, schema } from 'normalizr';
// Define a users schema
const user = new schema.Entity('users');
// Define your comments schema
const comment = new schema.Entity('comments', {
commenter: user
});
// Define your article
const article = new schema.Entity('articles', {
author: user,
comments: [ comment ]
});
const normalizedData = normalize(originalData, article);
フラット化されたデータは次のようになります.
{
result: "123",
entities: {
"articles": {
"123": {
id: "123",
author: "1",
title: "My awesome blog post",
comments: [ "324" ]
}
},
"users": {
"1": { "id": "1", "name": "Paul" },
"2": { "id": "2", "name": "Nicole" }
},
"comments": {
"324": { id: "324", "commenter": "2" }
}
}
}
real-wordのschema定義は次のとおりです。
APIを呼び出して返されるデータは,ユーザ情報,ユーザ配列,倉庫情報,倉庫配列である.
const userSchema = new schema.Entity('users', {}, {
idAttribute: user => user.login.toLowerCase()
})
const repoSchema = new schema.Entity('repos', {
owner: userSchema
}, {
idAttribute: repo => repo.fullName.toLowerCase()
})
export const Schemas = {
USER: userSchema,
USER_ARRAY: [userSchema],
REPO: repoSchema,
REPO_ARRAY: [repoSchema]
}
二、humps
アルパカの名前に変換
使用例:
humps.camelize('hello_world') // 'helloWorld'
humps.decamelize('fooBar') // 'foo_bar'
humps.decamelize('fooBarBaz', { separator: '-' }) // 'foo-bar-baz'
オブジェクトの変換
var object = { attr_one: 'foo', attr_two: 'bar' }
humps.camelizeKeys(object); // { attrOne: 'foo', attrTwo: 'bar' }
へんかんはいれつ
var array = [{ attr_one: 'foo' }, { attr_one: 'bar' }]
humps.camelizeKeys(array); // [{ attrOne: 'foo' }, { attrOne: 'bar' }]
コールバックを受け入れる
humps.camelizeKeys(obj, function (key, convert) {
return /^[A-Z0-9_]+$/.test(key) ? key : convert(key);
});
humps.decamelizeKeys(obj, function (key, convert, options) {
return /^[A-Z0-9_]+$/.test(key) ? key : convert(key, options);
});
反転
humps.decamelizeKeys(obj, {
separator: '-',
process: function (key, convert, options) {
return /^[A-Z0-9_]+$/.test(key) ? key : convert(key, options);
}
});
API:
humps.camelize(string)
humps.camelize('hello_world-foo bar') // 'helloWorldFooBar'
humps.pascalize(string)
humps.pascalize('hello_world-foo bar') // 'HelloWorldFooBar'
humps.decamelize(string, options)
humps.decamelize('helloWorldFooBar') // 'hello_world_foo_bar'
humps.decamelize('helloWorldFooBar', { separator: '-' }) // 'hello-world-foo-bar'
humps.decamelize('helloWorld1', { split: /(?=[A-Z0-9])/ }) // 'hello_world_1'
三、realword actionとstate変化
クエリーをクリックするとアクションの呼び出し順序
@@INIT初期化状態
entities:
users:{} 0 keys
repos:{} 0 keys
pagination:{} 2 keys
starredByUser:{} 0 keys
stargazersByRepo:{} 0 keys
errorMessage:null
USER_REQUEST要求githubユーザ情報
▶state:{} 3 keys
▶entities:{} 2 keys
users:{} 0 keys
repos:{} 0 keys
▶pagination:{} 2 keys
starredByUser:{} 0 keys
stargazersByRepo:{} 0 keys
errorMessage:null
STARRED_REQUEST要求githubユーザースター情報
▶action:{} 1 key
login:"csy512889371"
▶state:{} 3 keys
▶entities:{} 2 keys
users:{} 0 keys
repos:{} 0 keys
▶pagination:{} 2 keys
▶starredByUser:{} 1 key
▶csy512889371:{} 4 keys
isFetching:true
nextPageUrl:undefined
pageCount:0
ids:[] 0 items
stargazersByRepo:{} 0 keys
errorMessage:null
STARRED_SUCCESSスター情報の返却に成功しました
▶action:{} 2 keys
login:"csy512889371"
▶response:{} 3 keys
▶entities:{} 2 keys
▶users:{} 12 keys
▶repos:{} 13 keys
▶result:[] 13 items
nextPageUrl:null
▶state:{} 3 keys
▶entities:{} 2 keys
▶users:{} 12 keys
▶repos:{} 13 keys
▶pagination:{} 2 keys
▶starredByUser:{} 1 key
▶csy512889371:{} 4 keys
isFetching:false
nextPageUrl:null
pageCount:1
▶ids:[] 13 items
stargazersByRepo:{} 0 keys
errorMessage:null
USER_SUCCESSユーザー情報の返信成功
USER_SUCCESS
▶action:{} 1 key
▶response:{} 3 keys
▶entities:{} 1 key
▶users:{} 1 key
`▶csy512889371:{} 30 keys
result:"csy512889371"
nextPageUrl:null
▶state:{} 3 keys
▶entities:{} 2 keys
▶users:{} 13 keys
▶repos:{} 13 keys
▶pagination:{} 2 keys
▶starredByUser:{} 1 key
▶csy512889371:{} 4 keys
stargazersByRepo:{} 0 keys
errorMessage:null
APIコード解読
APIは中間キーとして使用
const configureStore = preloadedState => createStore(
rootReducer,
preloadedState,
applyMiddleware(thunk, api)
)
action :
Call API
endpoint
"users/csy512889371"
schema
EntitySchema {_key: "users", _getId: ƒ, _idAttribute: ƒ, _mergeStrategy: ƒ, _processStrategy: ƒ, …}
types
["USER_REQUEST", "USER_SUCCESS", "USER_FAILURE"]
export default store => next => action => {
// API
const callAPI = action[CALL_API]
if (typeof callAPI === 'undefined') {
return next(action)
}
//
let { endpoint } = callAPI
//schema
//types : 3 action。 、 api : API
const { schema, types } = callAPI
// endpoint 、shema 、types
if (typeof endpoint === 'function') {
endpoint = endpoint(store.getState())
}
if (typeof endpoint !== 'string') {
throw new Error('Specify a string endpoint URL.')
}
if (!schema) {
throw new Error('Specify one of the exported Schemas.')
}
if (!Array.isArray(types) || types.length !== 3) {
throw new Error('Expected an array of three action types.')
}
if (!types.every(type => typeof type === 'string')) {
throw new Error('Expected action types to be strings.')
}
// types 3 action。 action
const actionWith = data => {
const finalAction = Object.assign({}, action, data)
delete finalAction[CALL_API]
return finalAction
}
const [ requestType, successType, failureType ] = types
// action
next(actionWith({ type: requestType }))
// callAPI , 、
return callApi(endpoint, schema).then(
response => next(actionWith({
response,
type: successType
})),
error => next(actionWith({
type: failureType,
error: error.message || 'Something bad happened'
}))
)
}
callApiメソッド:
const callApi = (endpoint, schema) => {
// url
const fullUrl = (endpoint.indexOf(API_ROOT) === -1) ? API_ROOT + endpoint : endpoint
// post
return fetch(fullUrl)
.then(response =>
response.json().then(json => {
//
if (!response.ok) {
return Promise.reject(json)
}
const camelizedJson = camelizeKeys(json)
const nextPageUrl = getNextPageUrl(response)
//
return Object.assign({},
normalize(camelizedJson, schema),
{ nextPageUrl }
)
})
)
}