关于修改复杂数据结构的思考

注意

本文须要要求读者由 typescript 和 react 的相关知识才能理解!前端

若是在业务中遇到代码难梳理,逻辑错综复杂,维护性不高的状况,能够继续读一读,瞧一瞧react

TL;DR

在我业务中遇到过对复杂结构的数据修改,例如如今有一个数据结构以下(这些都是真实地业务中脱敏出来的)typescript

关于复杂数据的结构描述

interface complexData {
  complexDataUniqueId: string; // 复杂数据结构的 惟一id
  relatedDatas: OtherComplexData[];

  ...otherUnconsideredInfos; // 其余和本文无关的数据
}

interface OtherComplexData {
  otherComplexDataUniqueId: string; // 复杂数据结构2的 惟一id
  user_info: userInfo;

  ...otherUnconsideredInfos; // 其余和本文无关的数据
}

interface userInfo {
  user_id: string;
  user_name: string;
  age: number;
  user_follow_info: userFollowInfo;

  ...otherUnconsideredInfos; // 其余和本文无关的数据
}

interface userFollowInfo {
  relation_type: RelationType;

  ...otherUnconsideredInfos; // 其余和本文无关的数据
}

enum RelationType {
  // 互不关注
  NON_FOLLOW = 0,
  // 已关注
  FOLLOWED = 1,
  // 被关注
  FOLLOWING = 2,
  // 互相关注
  MUTUAL_FOLLOWING = 3
}
复制代码

正文

如上所示数据结构至关之复杂,一个复杂的数据结构中包含了另一个复杂的数据结构,另一种复杂的数据结构中包含了用户的信息,用户的信息中包含了该用户和当前登陆用户的关系数组

而后在如今业务上需求是,由一个 complexData[] 的数组,输入一个 otherComplexDataUniqueId 匹配到其对应的关联的数据,而后修改这个结构的用户关系(好比 从 互不关注 变成 已关注)微信

按照面向过程的思考方式,咱们能够很快的写出一段伪代码markdown

state = {
  complexDatas: [complexData, complexData, complexData, ...]
}

followSomeUser (targetId: string) {
  // 也许就在你的业务代码中也会像我同样,充斥着大量大段大段的相似这样的函数
  // 逻辑错综复杂,功能难以维护
  this.setState({
      complexDatas: complexDatas.map(item => {
      item.relatedDatas.map(cItem => {
        if (targetId === cItem.otherComplexDataUniqueId) {
          cItem = {
            ...cItem,
            cItem.user_info = {
              ...cItem.user_info,
              user_follow_info: {
                ...cItem.user_info.user_follow_info,
                relation_type: RelationType.FOLLOWED // 修改为已经关注
              }
            }
          }
        }
      })
    })
  })
}
复制代码

思路很清晰,保持全部其余的数据不变,并返回新的引用(react) 可是这样写实在是很是的复杂丑陋,让人摸不清逻辑,做者可能没几个月后也会忘记数据结构

因此,咱们在写业务代码中,须要能够很好的把代码逻辑拆分,下面让咱们来简单把上述的伪代码作一个拆分和解构ide

咱们把代码分红两个部分,查找 和 赋值函数

首先是查找,咱们能够把查找抽象成一个函数来作ui

// 函数式的查找须要修改的目标, 匹配目标id
const match = (o: otherComplexData, targetId: string) =>  o.otherComplexDataUniqueId === targetId;
复制代码
// 赋值(对于数据结构的更新,和更新补丁相似,因此叫patch)
const patchOtherComplexDataFollowRelation = (o: otherComplexData, relation_type: RelationType) => {
  return  {
    ...o,
    o.user_info = {
      ...o.user_info,
      user_follow_info: {
        ...o.user_info.user_follow_info,
        relation_type // 修改为已经关注
      }
    }
  }
}
复制代码

而后是遍历并修改

const updateList = (list: complexData[], targetId: string) => {
  return list.map(item => item.relatedDatas.map(cItem => { match(cItem, targetId) ? ...patchOtherComplexDataFollowRelation(cItem, RelationType.FOLLOWED) : cItem} ))
}
复制代码

让咱们完整地看看用函数式 + 解耦的方式写

state = {
  complexDatas: [complexData, complexData, complexData, ...]
}

followSomeUser (targetId: string) {
  const match = (o: otherComplexData, targetId: string) =>  o.otherComplexDataUniqueId === targetId;

  const patchOtherComplexDataFollowRelation = (o: otherComplexData, relation_type: RelationType) => {
    return  {
      ...o,
      o.user_info = {
        ...o.user_info,
        user_follow_info: {
          ...o.user_info.user_follow_info,
          relation_type // 修改为已经关注
        }
      }
    }
  }

  const updateList = (list: complexData[], targetId: string) => {
    return list.map(item => item.relatedDatas.map(cItem => { match(cItem, targetId) ? ...patchOtherComplexDataFollowRelation(cItem, RelationType.FOLLOWED) : cItem} ))
  }

  // 这样看起来是否是很是的清晰,让人易于理解?
  this.setState(s => ({ complexDatas: updateList(s.complexDatas) }))
}
复制代码

经过两种方式的比较,咱们能够明确认识到,当咱们平时业务中遇到一大段很是复杂的逻辑的时候,必定要学会梳理脉络 把复杂的逻辑多解耦,该拆分拆分,这样才能让咱们写的代码更具有更好的可读性和可维护性

广告

字节跳动IES招前端啦,有兴趣有能力的同窗能够加我微信:L_star07 私聊~

工做地点基本涵盖全国各大一线城市,欢迎您的到来呀

相关文章
相关标签/搜索