React学習ノート_realword

44654 ワード

一、normalizr扁平化データ


ステータスをフラット化したAPIを維持すると、ネストされたリソースが返されることがよくあります.これはFluxまたはReduxベースのアーキテクチャでは非常に困難に処理されます.normalizrのようなライブラリを用いてデータをフラット化し,状態をできるだけフラット化することを推奨する.

例:


典型的なAPI呼び出しはデータを返す:
  • 記事情報
  • 文字情報には、著者情報、コメントが含まれている.article: users and comments
  • {
      "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 }
                    )
                })
            )
    }