My MobX code is slower than the Redux version, what am I doing wrong? #3309
-
From my understanding, mobx is supposed to perform better than redux. However, I wrote two very simple programs that do the same thing: display 10000 textareas. One was was written with redux and the other with mobx. The mobx code is significantly slower. Could someone tell me what I'm doing wrong? Here is the mobx code import { makeAutoObservable } from "mobx"
import { observer } from "mobx-react"
class Data {
values = []
setValue(index, str) {
this.values[index] = str
}
getValue(index) {
if (index >= this.values.length) return undefined
return this.values[index]
}
constructor() {
makeAutoObservable(this)
}
}
const data = new Data()
const MDTextArea = observer(function MDTextArea({index}) {
const value = data.getValue(index)
return (
<textarea
key={"_m" + index}
onChange={(ev) => {
const txt = ev.target.value
data.setValue(index, txt)
}}
style={{ width: "300px", height: "100px" }}
wrap="hard"
value={value || ""}
/>
)
})
function Top() {
let ret = []
for (let i = 0; i < 10000; i++) {
ret.push(<MDTextArea key={"_k" + i} index={i} />)
}
return ret
}
function App() {
return <Top />
}
ReactDOM.render(<App/>, document.getElementById("root")) Here is the redux code: import { memo, useCallback } from "react"
import produce from "immer"
import { Provider, useSelector } from "react-redux"
import { createStore } from "redux"
const reducer = (state, action) => {
if (action.type === "set-value") {
return produce(state, (state) => {
state.values[action.index] = action.value
})
}
return state
}
const store = createStore(reducer, { values: [] })
const dispatch = store.dispatch
const MDTextArea = memo(function MDTextArea({ index, value }) {
return (
<textarea
key={"_m" + index}
onChange={(ev) => {
const txt = ev.target.value
dispatch({ type: "set-value", index, value: txt })
}}
style={{ width: "300px", height: "100px" }}
value={value}
/>
)
})
const Part = memo(function Part({ index }) {
const cb = useCallback((s) => s.values[index], [])
const value = useSelector(cb)
return <MDTextArea key={"_q" + index} index={index} value={value} />
})
function Top() {
let ret = []
for (let i = 0; i < 10000; i++) {
ret.push(<Part key={"_k" + i} index={i} />)
}
return ret
}
function App() {
return (
<Provider store={store}>
<Top />
</Provider>
)
}
ReactDOM.render(<App/>, document.getElementById("root")) |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 2 replies
-
Hi Jacques, the way you've structured the data means that Mobx is having re-render all textareas on each key press. You can see this if you turn on "Highlight updates when components render." in React DevTools. Hold on a minute and I'll update your example to avoid that. |
Beta Was this translation helpful? Give feedback.
-
Updated example below. One of the key things for Mobx performance is to make your observers observe as little as possible.
It takes little bit of planning at first to structure the code in the right way, but it quickly becomes second nature. You might be worried it's going to force your state classes into a weird shape, but it's quite the opposite in my experience - it tends to push towards a cleaner design. This approach is so important to making Mobx fast that it is covered in 3 out of the first 4 topics in the Optimizing React component rendering doc! Well worth a read. Anyway, hope that helps. import React from "react"
import { makeAutoObservable } from "mobx"
import { observer } from "mobx-react"
class Data {
value = ""
constructor() {
makeAutoObservable(this)
}
}
const MDTextArea = observer(function MDTextArea({data}) {
return (
<textarea
onChange={(ev) => {
const txt = ev.target.value
data.value = txt
}}
style={{ width: "300px", height: "100px" }}
wrap="hard"
value={data.value || ""}
/>
)
})
const numData = 10000
const allData = []
for (let i = 0; i < numData; i++ ) {
allData.push(new Data())
}
function Top() {
let ret = []
for (let i = 0; i < numData; i++) {
ret.push(<MDTextArea key={"_k" + i} data={allData[i]} />)
}
return ret
}
function App() {
return <Top />
}
ReactDOM.render(<App/>, document.getElementById("root")) |
Beta Was this translation helpful? Give feedback.
Updated example below.
One of the key things for Mobx performance is to make your observers observe as little as possible.
Data
to update, and allMDTextArea
s observed that. This forced a render of all textareas even though only one needed to update.Data
and only causes oneMDTextArea
/ textarea to update.It takes little bit of planning at first to structure the code in the right way, but it quickly becomes second nature. You might be worried it's going to force your state classes into a weird shape, but it's quite the opposite in my experience - it tends to push towards a…