normalizr 学习笔记 --- node.js开发

来源:互联网 发布:娇喘合集 网络歌手 编辑:程序博客网 时间:2024/06/05 18:57

normalizr 学习笔记 — node.js开发

最近开始学习node.js开发,有很多基础知识和框架需要学习,所以打算将自己学习笔记记录下来,即可以和大家分享,也可以方便自己以后回顾知识。由于只是个人笔记,便不是详细的教程,有不懂的代码还请自行百度。


主要模块

  • normalizr

介绍

该模块主要将获取的数据进一步格式化,在store创建一个虚拟数据库,数据通过id引用

代码段

由于我学习时是配合redux进行使用的,所以这里主要是在redux的基础上进行讲解的,redux的相关内容可参考Redux 学习笔记 — node.js开发,或者自行查找自动学习。

我使用了redux官方的例子real-world中的部分源码,大家可以配合这个学习

import api from '../api'...applyMiddleware(thunk, api, createLogger())

添加real-world的api中间组件

import { Schema, arrayOf, normalize } from 'normalizr'

在api中导入normalizr模块

const historySchema = new Schema('historys', {  idAttribute: history => history.ContractID})const userScheme = new Schema('users', {  idAttribute: user => user.UserID})const replySchema = new Schema('replys', {  idAttribute: reply => reply.ReplyID})userScheme.define({  history: historySchema})historySchema.define({  reply: replySchema})

数据结构定义,define()定义包含的schema

export const Schemas = {  HISTORY: historySchema,  HISTORY_ARRAY: arrayOf(historySchema),  REPLY: replySchema,  REPLY_ARRAY: arrayOf(replySchema),  USER: userScheme,  USER_ARRAY: arrayOf(userScheme)}

输出数据结构模板,arrayOf()模板数组化

const API_ROOT = 'http://localhost/app/'function callApi(endpoint, schema, method, form) {  const fullUrl = (endpoint.indexOf(API_ROOT) === -1) ? API_ROOT + endpoint : endpoint  let requestType;  if (method === 'POST') {    requestType = {      method: method,      body:form    }  } else if (method === 'GET') {    requestType = null  }  return fetch(fullUrl, requestType)    .then(response => {      return response.json()        .then(json =>          ({ json, response })        )    })    .then(({ json, response }) => {      if (!response.ok) {        // 回调规范的处理失败格式        return Promise.reject(json)      }      if (json.code !== 200) {        // 回调规范的处理失败格式        return Promise.reject(json)      }      return Object.assign({},normalize(json.data, schema))    })}

根据action传过来的参数,进行不同的网络请求,请求成功后的数据通过normalize()进行转换

// action keyexport const CALL_API = 'CALL_API'export default store => next => action => {  const callAPI = action[CALL_API]  if (typeof callAPI === 'undefined') {    return next(action)  }  let { endpoint, method, form } = callAPI  const { schema, types } = callAPI  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.')  }  function actionWith(data) {    const finalAction = Object.assign({}, action, data)    delete finalAction[CALL_API]    return finalAction  }  const [ requestType, successType, failureType ] = types  next(actionWith({ type: requestType }))  return callApi(endpoint, schema, method, form).then(    response => next(actionWith({      response,      type: successType    })),    error => next(actionWith({      type: failureType,      error: error.message || 'Something bad happened'    }))  )}

分为3个action请求阶段,requestType, successType,failureType,根据callApi()返回的结构进行异步调用,此时数据已经存入store中的虚拟数据库,之后将action传给真正的reduce将id数据存入

import _ from 'lodash'...function entities(state = {  users: {},  historys: {},  replys: {}}, action) {  if (action.response && action.response.entities) {    return _.merge({}, state, action.response.entities)  }  return state}

这里用到lodash模块的merge,将所有请求获取到的数据和store虚拟数据库进行合并更新

const pagination = combineReducers({  historyBySection: paginate({    mapActionToKey: action => action.section,    types: [      ActionTypes.HISTORY_REQUEST,      ActionTypes.HISTORY_SUCCESS,      ActionTypes.HISTORY_FAILURE    ]  }),  replyByHistory: paginate({    mapActionToKey: action => action.historyId,    types: [      ActionTypes.REPLY_REQUEST,      ActionTypes.REPLY_SUCCESS,      ActionTypes.REPLY_FAILURE    ]  })})

根据不同类型实现数据分页的接口,mapActionToKey作为类型指针,type接收的ActionTypes

import merge from 'lodash/merge'import union from 'lodash/union'// Creates a reducer managing pagination, given the action types to handle,// and a function telling how to extract the key from an action.export default function paginate({ types, mapActionToKey }) {  if (!Array.isArray(types) || types.length !== 3) {    throw new Error('Expected types to be an array of three elements.')  }  if (!types.every(t => typeof t === 'string')) {    throw new Error('Expected types to be strings.')  }  if (typeof mapActionToKey !== 'function') {    throw new Error('Expected mapActionToKey to be a function.')  }  const [ requestType, successType, failureType ] = types  function updatePagination(state = {    isFetching: false,    ids: []  }, action) {    switch (action.type) {      case requestType:        return merge({}, state, {          isFetching: true        })      case successType:        return merge({}, state, {          isFetching: false,          ids: union(state.ids, action.response.result),        })      case failureType:        return merge({}, state, {          isFetching: false        })      default:        return state    }  }  return function updatePaginationByKey(state = {}, action) {    switch (action.type) {      case requestType:      case successType:      case failureType:        const key = mapActionToKey(action)        if (typeof key !== 'string') {          throw new Error('Expected key to be a string.')        }        return merge({}, state, {          [key]: updatePagination(state[key], action)        })      default:        return state    }  }}

实现数据分页方法,配合了normalizr

function mapStateToProps(state, ownProps) {  const section = ownProps.section;  const {    pagination: { historyBySection },    entities: { historys }  } = state;  const historyPagination = historyBySection[section] || { isFetching: true, ids: [] }  const items = historyPagination.ids.map(id => historys[id])  return {    historyPagination,    items  }}

根据分页指针和reduce中的id,从store虚拟数据库中获取真正的数据

部分代码来自于redux官方例子real-world

3 0