React学习笔记_realword

一、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 变化

点击查询后 action 的调用顺序

@@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 }
                )
            })
        )
}

你可能感兴趣的:(【前端,react】)