This is the sixth day of my participation in Gwen Challenge

Page bookmarks

Basically, you scroll from the current page, and when you “go out” and come back, you restore the scroll position, like a bookmark in a book.

Describe your expectations for page bookmarks

  1. When I jump to another page, I come back to undo it.
  2. Restoration can not be directly positioned too abrupt, should be animation.

Then set about fulfilling expectations

How to achieve”When I jump to another page, I come back to undo it.

Push the idea down:

  1. “Recovery” depends on “data”.
  2. “Data” is “saved” as it jumps from page to page
  3. “Save” is something that needs to be out of the page and out of its “control.
  4. Who is needed to “control” 🤔??

Easy ah, that is obviously handed over to the data warehouse by 😄.

How to achieve”Restoration can not be directly positioned too abrupt, should be animation.

Push it again:

  1. “Animation” needs to be “delicate”.
  2. Subtlety requires coherence.
  3. Coherence requires recursion.
  4. Who is needed to “recurse” 🤔??

After exploration, the requestAnimationFrame for the Bom object is a good fit.

requestAnimationFrame

Tell the browser that you want to execute an animation and ask the browser to call the specified callback to update the animation before the next redraw. This method takes as an argument a callback function that is executed before the browser’s next redraw

If the screen is 60 FPS per second, the callback function is usually executed 60 times per second (except for missing frames), which is “consistent” enough, and if you don’t make any changes at all, it’s “fine” (just like game development).

It must be emphasized here that I have looked up several articles, and many of them have made a mistake (I think).

Like this one:

You say that like setinterval, I think it is wrong, logical contradiction.

If the page is 60fps per second, then you execute requestAnimationFrame only once the next time the screen is drawn, then how coherent is that, that’s by recursively executing this function, that’s what the code says. It won’t lie.

The code:

export function sineaseOut(t, b, c, d) {
    return c * ((t = t / d - 1) * t * t + 1) + b
}
export function scrollToView(scroller, value) {
    if(! scroller) {return
    }

    const scroll = value
    const scrollStart = 0
    let start = null
    const step = (timestamp) = > {
        if(! start) { start = timestamp }let stepScroll = sineaseOut(timestamp - start, 0, scroll, 500)
        let total = scroller.scrollTop = scrollStart + stepScroll
        if (total < scrollStart + scroll) {
            requestAnimationFrame(step)
        }
    }
    requestAnimationFrame(step)
}
Copy the code

So let’s make a summary

  • State data is handled by Mobx, the data manager, and Mobx sends the Global repository.

  • Animation refinement is achieved by recursively calling requestAnimationFrame with 60 draws per second.


That makes sense. And then what?

Oh, yes… There is a solution to both, but the most important question remains: where does it work??

“The place of use” but very see “feng shui” oh

If you don’t choose the right location, your code will be full of affectation, just to look good, which is the equivalent of trying to look fat.

The most dangerous traps are often gentle

First of all from the demand point of view, it is easy to associate to unload and mount components, because really match, this is the biggest temptation, because it can achieve, but it is not a good way, at least not the best, because if you really do it, so that all the page components to write this repetitive logic, that’s too tired, If you add to a project that already has a lot of pages written, you’ll crash and that’s not acceptable.

Catch the silver lining

When I think about it, after several twists and turns, almost “really sweet”, finally let me think of an excellent position, that is.

history.listen

At that time that moment, I confidently mouth slightly up, steady 😄.

So let’s go to the code, and I’m sure the b number is in your head, so I don’t have to say anything more.

    let history = useHistory();
    let location = useLocation();
    const {
        global: { current, scrollData, changeParams },
    } = store;
    useEffect(() = > {
        const { pathname, search } = location;
        changeParams({
            current: decodeURIComponent(pathname + search)
        })
        if(! history._listenCount) { history._listenCount++; history.listen((locationState, type) = > {
                const {
                    global: { current, scrollData, changeParams },
                } = store;
                let node = document.getElementsByClassName('ant-layout-content') [0]
                if(! node) {return
                }
                // node.scrollTop = 0;
                // Save the Key of the latest page
                let newkey = decodeURIComponent(locationState.pathname + locationState.search);
                /* see if there are any recorded values */
                let recordValue = scrollData[newkey]
                if (typeof recordValue === 'number') {
                    scrollToView(node, recordValue)
                }
                // Save the value (past), old
                let oldKey = current;
                letscrollDataTemp = { ... toJS(scrollData), [oldKey]: node.scrollTop }if (type === "POP") {
                    // Node. scrollTop is already set to 0 for POP
                    changeParams({
                        current: newkey,
                    })
                } else {
                    changeParams({
                        current: newkey,
                        scrollData: scrollDataTemp
                    })
                }
            })
        }
    }, [])
Copy the code

The code is very clear, is the page to go, record, page back, restore, the solution is so simple and natural.


Look at the effect


conclusion

By exploring how bookmarking can be implemented on your page, you can better understand the truth that there is more than one way to achieve it. By knowing what you want, you will know what to insist on and how to do it, and you will be more likely to catch the silver lining.

🌰 integrates this functionality