

A MobX-State-Tree shortcut for setter actions
source link: https://shift.infinite.red/a-mobx-state-tree-shortcut-for-setter-actions-ac88353df060
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

A MobX-State-Tree shortcut for setter actions
MobX-State-Tree property setters are kind of annoying. Here’s a nice shortcut to create them automatically.

If you’ve used MobX-State-Tree (as we generally like to do at Infinite Red), you’ll know that you can’t assign to properties outside of an action.
import { types } from "mobx-state-tree"const UserModel = types.model("User", {
name: types.string,
age: types.number
})const user = UserModel.create({ name: "Jamon", age: 40 })
user.name = "Joe" // error! must be in an action
The reason for this is to ensure that assignments are “batched” properly before you update your UI. It also makes sure that changes generate actions for onAction
listeners properly.
It’s also problematic in async actions, as you can’t set properties directly in those either:
import { types } from "mobx-state-tree"const UserModel = types.model("User", {
name: types.string,
age: types.number
})
.actions(self => ({
async fetchData() {
const data = await getData()
self.name = data.name // NOPE! Not in an action anymore
},
}))const user = UserModel.create({ name: "Jamon", age: 40 })
user.setName("Joe") // all good!
Generally speaking, the way we solve that is by making a setter action for each property:
import { types } from "mobx-state-tree"const UserModel = types.model("User", {
name: types.string,
age: types.number
})
.actions(self => ({
setName(newName: string) {
self.name = newName
},
setAge(newAge: number) {
self.age = newAge
}
}))const user = UserModel.create({ name: "Jamon", age: 40 })
user.setName("Joe") // all good!
This is a bit tedious and feels like it shouldn’t be necessary. Not only that, but every time you add a new property, you have to add another setter action.
While you can turn off the action protection entirely, there’s a safer way to do this!
import { types} from "mobx-state-tree"const UserModel = types.model("User", {
name: types.string,
age: types.number
})
.actions(self => ({
setProp(field, newValue) {
self[field] = newValue;
}
}))const user = UserModel.create({ name: "Jamon", age: 40 })
user.setProp("name", "Joe") // all good!// but typescript thinks this is fine? uh-oh
user.setProp("age", "shouldn't work")
This works pretty well, but what about TypeScript protections? After all, we have different types for age
and name
.
Just use this:
import { types, SnapshotIn } from "mobx-state-tree"const UserModel = types.model("User", {
name: types.string,
age: types.number
})
.actions(self => ({
setProp<
K extends keyof SnapshotIn<typeof self>,
V extends SnapshotIn<typeof self>[K]
>(field: K, newValue: V) {
self[field] = newValue;
}
}))
const user = UserModel.create({ name: "Jamon", age: 40 })
user.setProp("name", "Joe") // all good!// typescript will error, like it's supposed to
user.setProp("age", "shouldn't work")
Try this out, and if you think it’s worthwhile enough, let me know on Twitter. Maybe we could include something like it in MobX-State-Tree core at some point!
Note: Timo Zöller published a very similar article about this a couple years ago, but I only found it after writing my version.
Note about Ignite: this helper will be included by default in Ignite v8 (code-named Maverick).
Recommend
-
37
每日前端夜话 0x92 每日前端夜话,陪你聊前端。 每天晚上18:00准时推送。 正文共:1602 字 预计阅...
-
12
getter 和setter 子类中为什么要写get和set方法获取释放数据,不写会怎样?在什么情况下要用getter和setter? getter通常与一个私有的实例变量对应,用于返回该变量的值
-
13
-
41
QQA: 为什么 java 中要写 getter/setter?java 有一个不成文的规定,如果要访问一个类的 private 字段,就需要写 getter/setter 方法。但我们在其它语言却很少见到类似的约定,为什么? 它是“封装”的体现,对外隐藏了具体实现...
-
14
Drop this before validation and just use a setter methodHi, weʼre arkency 👋 In many projects you can see code such as: class Something before_vali...
-
9
C# 9 新特性——init only setter Intro# C# 9 中新支持了 init 关键字,这是一个特殊的 setter,用来指定只能在对象初始化的时候进行赋值,...
-
14
Define a public bean variable in the spring without using a setter advertisements I read on a few websites that with Spring its possible to do...
-
11
Disallow returning values from setters (no-setter-return)The "extends": "eslint:recommended" property in a configuration file enables this rule.Setters cannot return values.While returning a value from a se...
-
10
Closed Bug 1687235 Opened 1 month ago Closed 25 days ago...
-
7
BackState management in React with MobXMay 12th, 2022 · 4 min read
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK