Article: MobX likes mutability. React does not #3252
Replies: 2 comments 9 replies
-
This is a little bit misleading, the immutable update would normally "solve" the problem, you would just loose the fine grained subscriptions mechanism - it would re-render whole subtree (and invalidate the
Passing primitives is a good recommendation, but
Not a good suggestion, don't run side effects in render.
This is imo the best way to go if the effect doesn't depend on Note these problems are well detectable with I am trying to address these here: Feedback welcome. |
Beta Was this translation helpful? Give feedback.
-
I'd like to share how we use MobX with React in our projects - these projects' sizes vary from thousands to ten thousands lines (of Typescript & React code), so we've gone through most of the problems introduced in above article. For simple components (with simple state & logic), we use React state ( For complex components, which always consist of complex state & logic among these states, we use MobX — it helps us make state logic simpler & more testable, in contrast to hooks like Here is a sample how we do this: // We make a hook names `useLocalStore`,
// which do simple binding between local store and component: init & dispose
function useLocalStore() {}
// and a base class `Store`, which provides some basic abilities like `init`, `collectDisposer`, ...
abstract class Store {}
// `LocalStoreForCounter` is a store class which holds local state & logic for component `Counter`, which inherits from base class `Store`
// When we do component testing, it's easy to test state logic (the local store) separately
class LocalStoreForCounter extends Store {
// I like class & decorator personally, though the spec for decorator is a headache
@observable num = 0
@action.bound increase() {
this.num++
}
// `init` is a abstract method defined on base class `Store`,
// which will be called when corresponding component mounted (the time for effect)
// Almost all effects of one component will be implemented here, because the MobX way (such as `reaction` / `autorun`)
// is apparently easier to use than the React way (such as `useEffect`)
init() {
// `collectDisposer` is a method provided by base class `Store`
// which collects all disposers and do dispose when corresponding component unmounts
this.collectDisposer(reaction(
() => this.num,
num => console.log(num)
))
}
}
// For complex components, all its states & state-related logic should be placed in local store class, instead of React state
// so inter-ops between MobX state and React state are avoided
export default observer(function Counter() {
const store = useLocalStore(LocalStoreForCounter)
return (
<p>
num: {store.num}
<button onClick={store.increase}>Increase</button>
</p>
)
}) We also made a DI tool to simplify dependencies among local stores, global stores and React components. But that is not related with topic here, so details are omitted in upper sample codes. Overall, we made a convention on when and how to use MobX state in React project, which avoids most of the inter-op problems and gives us capability to maintain complex component logic. |
Beta Was this translation helpful? Give feedback.
-
Hey guys, just recently posted an article about the integration with MobX and React. When I started playing with both, coming from Redux, I was used to the "immutable" way of doing things. That made me struggle with some small things. So maybe this article is helpful to some people out there.
Let me know what you think and any possible mistakes of mine 😛
Article here 👈🏽
Beta Was this translation helpful? Give feedback.
All reactions