Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
545 views
in Technique[技术] by (71.8m points)

reactjs - Mobx Store shows lag in nested input range. Causes slow performance

I have a simple MobX store with padding & padding2, the difference is one is an object:

import { observable, action, makeObservable } from "mobx"

export type Padding2 = {
    horizontal: number
    vertical: number
}

export interface IStore {
    padding: number
    updatePadding({ padding }: { padding: number }): void
    padding2: Padding2
    updatePadding2({ horizontal, vertical }: Partial<Padding2>): void
}

export class Store implements IStore {
    padding = 100
    padding2 = {
        horizontal: 100,
        vertical: 50,
    }

    constructor() {
        makeObservable(this, {
            padding: observable,
            updatePadding: action.bound,
            padding2: observable,
            updatePadding2: action.bound,
        })
    }

    updatePadding({ padding }: { padding: number }) {
        this.padding = padding
    }

    updatePadding2({ horizontal, vertical }: Partial<Padding2>) {
        if (horizontal) this.padding2.horizontal = horizontal
        if (vertical) this.padding2.vertical = vertical
    }
}

export const store = new Store()

And I have a simple <input type="range" /> like:

import * as React from "react"
import { observer } from "mobx-react"

import "./styles.css"
import { useStore } from "./context"

const App = () => {
    const store = useStore()
    const { padding, updatePadding, padding2, updatePadding2 } = store

    return (
        <div>
            <h1>MobX Slow Perf for Range</h1>
            <h2>Padding</h2>
            <input
                type="range"
                name="padding"
                value={padding}
                onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
                    const padding = Number(e.target.value)
                    updatePadding({
                        padding,
                    })
                }}
            />
            <span>{padding} px</span>

            <h2>Padding2</h2>
            <input
                type="range"
                name="horizontal"
                value={padding2.horizontal}
                onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
                    const horizontal = Number(e.target.value)
                    updatePadding2({
                        horizontal,
                    })
                }}
            />
            <span>{padding2.horizontal} px</span>
        </div>
    )
}

export default observer(App)

When I use the slider on padding (the 1st slider) it goes from 100 to 0 smoothly but when I do it on padding2 (the 2nd slider) it shows noticeable lag.

mobx slow perf

Here's a minimal Codesandbox → https://codesandbox.io/s/mobx-range-slow-perf-3zobu?file=/src/App.tsx

How do I solve it without using another local state like React.useState() for padding2?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The subtle bug here is that updatePadding checks if horizontal or vertical are truthy. This means that the value of 0 returns false, and the store isn't updated at all then. As a result, when you quickly drag it left, the slider jumps to 0 but its value isn't updated.

To fix this, you'll want to explicitly check if they're undefined

updatePadding2({ horizontal, vertical }: Partial<Padding2>) {
  if (horizontal !== undefined) this.padding2.horizontal = horizontal;
  if (vertical !== undefined) this.padding2.vertical = vertical;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...