[Recoil] Intermediate Selectors

 

interface:

export type ElementStyle = {
    position: {top: number; left: number}
    size: {width: number; height: number}
}

export type Element = {style: ElementStyle; image?: {id: number; src: string}}

 

Let's say we have this selector:

const imageInfoState = selector({
    key: 'imageInfoState',
    get: ({get}) => {
        const id = get(selectElementAtom)
        if (id === null) return

        const element = get(elementAtom(id))
        const imageId = element.image?.id
        if (imageId === undefined) return

        return callApi('image-details', {queryParams: {seed: imageId}})
    },
})

So everytime when Element changes, for example when we drag the image, position will changed,  the callApi will be triggered.

It will cause the component being re-renderred too many times.

 

How to solve the problem?

const element = get(elementAtom(id))

This code will be update everytime when Element position changes.

But we don't want trigger callApi if imageId doesn't change.

We can use intermediate selector:

const imageIdState = selector({
    key: 'imageId',
    get: ({get}) => {
        const id = get(selectElementAtom)
        if (id === null) return

        const element = get(elementAtom(id))
        return element.image?.id
    },
})

const imageInfoState = selector({
    key: 'imageInfoState',
    get: ({get}) => {
        const imageId = get(imageIdState) // use intermediate selector
        if (imageId === undefined) return

        return callApi('image-details', {queryParams: {seed: imageId}})
    },
})

 

posted @ 2022-10-11 02:17  Zhentiw  阅读(24)  评论(0编辑  收藏  举报