Recently received a demand, the product manager hopes to add pop-up advertisements, and advertisements can pop up and display on any page of the application according to the background configuration. When the number of advertisements, links or target pages on the current page is changed in the background, the data on the current page is modified without affecting the data on other pages

For example, in the background setting, the "Home" ad appears once, and the "My" page ad appears 3 times. After the user enters, the "Home" ad is closed once, and the "My" page ad is closed twice. At this point, if you exit the app and set the "Home" ad to 2 times in the background, then the user's "Home" ad will be reset to 2 times, and the "My" page ad will still be 1 time (3 - 2)

demand analysis

The data returned by the backend must be an array, and each object will have three parameters: the target page (displayed page ), the jump link , and the total number of occurrences . The front end needs to process the data:

  • When there is no local data (the first entry), assign the total number of occurrences to a parameter firstTotalTimes (record the original total number of occurrences)
  • When there is data locally (not the first entry)

    1. Clear the firstTotalTimes in the local storage and assign the return value to removeLocalTotalTimeList
    2. Compare the removeLocalTotalTimeList with the data advertisementList returned by the request

      • If it is equal, it means that the background data has not changed. Check whether the total number of occurrences in your local storage is greater than 0. If it is greater, the advertisement will be displayed.
      • If it is not equal, it means that the data has been modified in the background. It needs to be analyzed here. Only the page where the modification is made is reset, and the unmodified place will not be processed.

The framework used by the author is umi3, which has the concept of wrappers, that is, a high-level component package for configuring routing. After adding it to umi.conf, any page must go through this first. The key code is as follows:

 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)
                    }
                }
            })
        }
    }
                                                                     })
}, [])

difficulty

Data Mutability in JS

The first pit point is that the data in JS is variable, so it is necessary to make a deep copy of its data so that it will not affect other data. Here I use the simplest deep copy: JSON.parse(JSON.stringify)

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

Determine which data modification in the background

It has been stated in the previous statement that when the local storage and the requested data are inconsistent, it is necessary to judge which pages should be reset and which pages should remain in the original state. This is to compare the two arrays, the easiest way is to do a double loop (On2).

First const cloneList = JSON.parse(JSON.stringify(resData.advertisementList)); , deep copy the data returned in the background, so that the original data will not be affected when the cloneList is processed. cloneLocalAdvertisementList is the local storage

if (_.isEqual(cloneList[i].pkId, cloneLocalAdvertisementList[j].pkId)) , pkId is the unique identifier of the advertisement, first identify each object in the array, which is one-to-one correspondence, and then judge if (_.isEqual(cloneList[i], cloneLocalAdvertisementList[j])) , compare the value in the object, if it is true, That is completely equal, indicating that the background data has not changed, then assign the firstTotalTimes in the local storage to the firstTotalTimes on the cloneList. If it is false, it means that the background has been modified, and reset the firstTotalTimes to the totalTimes in this pull data

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

The above is the core code of this project. Of course, the difference between opening the app and opening WeChat, and the data update after logging in when not logged in, etc., can be judged by monitoring the login. (useEffect depends on data) implementation

Summarize

This time I was pitted by data variability, and I checked it through the debugger.

Double loops are not used many times in actual projects, so make a note of this


山头人汉波
394 声望555 粉丝