最近接到一个需要,产品经理心愿能新增弹窗广告,广告可依据后盾配置在利用任意页面弹出展现。当后盾扭转以后页面广告次数、链接或者指标页后,以后页面数据批改,不影响其余页面数据

例如后盾设置“首页”呈现广告 1 次,“我的”页面广告呈现 3 次,用户进去后敞开了“首页”广告 1 次,敞开了“我的”页面广告 2 次。此时退出利用,后盾将“首页”广告设置为 2 次,那么该用户“首页”广告重置为 2 次,“我的”页面广告仍为 1 次( 3 - 2)

需要剖析

后端返回的数据必然是个数组,每个对象中会有指标页(展现的页面),跳转链接总呈现的次数三参数。前端要对数据进行解决:

  • 当本地没有数据时(第一次进入),将总呈现次数赋值给一参数 firstTotalTimes(记录原总呈现次数)
  • 当本地有数据(非第一次进入)

    1. 将本地存储中的 firstTotalTimes 革除,返回值赋值为 removeLocalTotalTimeList
    2. 将 removeLocalTotalTimeList 与 申请返回的数据 advertisementList 进行比照

      • 相等,阐明后盾数据没有扭转,查看你本地存储中的总呈现次数是否大于 0 ,大于则展现广告
      • 不相等,阐明后盾批改了数据,这里还要剖析,只重置批改处页的,未修改的中央不做解决

笔者用的框架是 umi3,其中有 wrappers 概念,即一个配置路由的高阶组件封装,在 umi.conf 中加上后,任何页面都要先通过这一道。要害代码如下:

useEffect(() => {    dispatch({ type: 'common/fetchGetPopUpAdvertisementList' }).then((resData: any) => {        if (resData?.resultCode === "S00000") {            if (!localStorage.advertisementList) {            const addFirstTotalTimes = resData.advertisementList.map((item: any) => {                item.firstTotalTimes = item.totalTimes                return item;            })            localStorage.advertisementList = JSON.stringify(addFirstTotalTimes);        }        const localAdvertisementList = JSON.parse(localStorage.advertisementList)        const cloneLocalAdvertisementList = JSON.parse(JSON.stringify(localAdvertisementList))        const removeLocalTotalTimeList = cloneLocalAdvertisementList.map((item: any) => {            delete item.firstTotalTimes            return item        })        if (_.isEqual(removeLocalTotalTimeList, resData.advertisementList)) {            console.log('相等')            localAdvertisementList.filter((item: any) => {                if (item.targetUrl.indexOf(history.location.pathname) > -1) {                    if (item.firstTotalTimes > 0) {                        setAdItem(item)                    }                }            })        } else {            console.log('不相等')            const cloneList = JSON.parse(JSON.stringify(resData.advertisementList));            for (let i = 0; i < cloneList.length; i++) {                for (let j = 0; j < cloneLocalAdvertisementList.length; j++) {                    if (_.isEqual(cloneList[i].pkId, cloneLocalAdvertisementList[j].pkId)) {                        if (_.isEqual(cloneList[i], cloneLocalAdvertisementList[j])) {                            cloneList[i].firstTotalTimes = localAdvertisementList[j].firstTotalTimes                        } else {                            cloneList[i].firstTotalTimes = cloneList[i].totalTimes                        }                    }                }            }            localStorage.advertisementList = JSON.stringify(cloneList);            cloneList.filter((item: any) => {                if (item.targetUrl.indexOf(history.location.pathname) > -1) {                    if (item.firstTotalTimes > 0) {                        setAdItem(item)                        setIsShow(true)                    }                }            })        }    }                                                                     })}, [])

难点

JS 的数据可变性

第一个坑点在 JS 的数据是可变的,所以要对其数据进行深拷贝,才不会影响到其余数据,这里我用了最简略的深拷贝:JSON.parse(JSON.stringify)

const cloneLocalAdvertisementList = JSON.parse(  JSON.stringify(localAdvertisementList),)

判断后盾那个数据批改

在之前表述中曾经表明,当本地存储和申请过去的数据不统一时要判断,哪要做重置,哪些页面则维持原状。这就要对两个数组进行比照,最简略的办法就是做双循环(On2).

const cloneList = JSON.parse(JSON.stringify(resData.advertisementList));,深拷贝后盾返回数据,这样对 cloneList 进行解决时就不会影响到原数据。cloneLocalAdvertisementList 则是本地的存储

if (_.isEqual(cloneList[i].pkId, cloneLocalAdvertisementList[j].pkId)) ,pkId 是广告惟一标识,先辨认数组中的每一个对象,这是一一对应的,再判断 if (_.isEqual(cloneList[i], cloneLocalAdvertisementList[j])) ,比照对象中的值,如果是 true,即齐全相等,阐明后盾数据没有变动,那就将本地存储中的 firstTotalTimes 赋值给 cloneList 上的 firstTotalTimes 。如果是 false,阐明后盾曾经批改,就把 firstTotalTimes 重置为本次拉取数据中的 totalTimes

const localAdvertisementList = JSON.parse(localStorage.advertisementList)const cloneLocalAdvertisementList = JSON.parse(JSON.stringify(localAdvertisementList)) ...const cloneList = JSON.parse(JSON.stringify(resData.advertisementList));for (let i = 0; i < cloneList.length; i++) {    for (let j = 0; j < cloneLocalAdvertisementList.length; j++) {        if (_.isEqual(cloneList[i].pkId, cloneLocalAdvertisementList[j].pkId)) {            if (_.isEqual(cloneList[i], cloneLocalAdvertisementList[j])) {                    cloneList[i].firstTotalTimes = localAdvertisementList[j].firstTotalTimes                } else {                    cloneList[i].firstTotalTimes = cloneList[i].totalTimes            }        }    }}

以上,就是对这次我的项目的外围代码,当然,还要思考到 App 端关上和 微信关上的差别,以及当未登录状态下的去登录后数据的更新等等,但这些能够通过监听登录来判断(useEffect 依赖数据)实现

总结

这次被数据可变性坑了,通过 debugger 来排查

双循环在理论我的项目中用的次数不多,所以对此做记录