Mobx-state-tree: Is it possible to assign by identifier?

Created on 24 Dec 2018  Â·  15Comments  Â·  Source: mobxjs/mobx-state-tree


_Question_

  • [x] I've checked documentation and searched for existing issues
  • [x] I tried the spectrum channel

The code below doesn't work. Is it possible to do something similar that does work? Or should I find the item I need in the store and then assign that? (The item in question belongs to another store btw. Not sure if this is good practice).

import { types } from 'mobx-state-tree'
import { Item } from 'src/features/items/ItemStore'

export const NotebookStore = types
  .model('NotebookStore', {
    selectedInvestigation: types.reference(Item),
  })
  .actions(self => ({
    selectInvestigation(investigationId?: number) {
      self.selectedInvestigation = investigationId
    },
  }))
question stale

Most helpful comment

In the example above: I get a ts-error in the selectItem action.

Yeah, you need to do

self.selectedItem = itemId as any

when itemId is a string currently sadly

I actually want to write a RFC for a new way to use identifiers so they are more TS friendly, but sadly it would be a breaking change

something like

const M = types.model({ ref: types.reference(whateverType) })

const m = M.create({ ref: "123" })

m.ref.valid // true if the ref is not broken, false if it is broken

m.ref.get() // gets the object pointed at, throws if the ref is not valid
m.ref.getId() // gets the id the ref is pointing to

m.ref.set(obj | id) sets the ref to point to a given object (if obj) or to a given id (if string or number), throws if the given obj or id is invalid
// alternatively
m.ref.set(obj) + m.ref.setId(id)

Technically it could also be done by adding a new ref type (or actually two with safeReference), but that'd mean we'd end up with 4 possible ref types

All 15 comments

Hi!
You should have Item somewhere in your tree, i.e.

.model('NotebookStore', {
    selectedInvestigation: types.reference(Item),
    items: types.array(Item)
  })

or use custom reference to resolve it from another tree (docs).

That didn't answer the question though. How would i set it in action even
if it was in the same tree? And why must it be in the same tree?

On Tue, 25 Dec 2018, 00:14 Gleb <[email protected] wrote:

Hi!
You should have Item somewhere in your tree, i.e.

.model('NotebookStore', {
selectedInvestigation: types.reference(Item),
items: types.array(Item)
})

or use custom reference to resolve it from another tree (docs
https://github.com/mobxjs/mobx-state-tree#customizable-references).

—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/mobxjs/mobx-state-tree/issues/1123#issuecomment-449774416,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AC8oX3SvOtpb0hdMKRYeSVl1qaHc98aVks5u8VHhgaJpZM4Zgp2k
.

Tried putting it in the same tree as part of a subtree and didn't help either.

Assuming you have:

const Item = types.mode('Notebook', {
  id: types.identifier,
  model: types.string,
  manufacturer: types.string,
})
const NotebookStore = types.model('NotebookStore', {
    selectedItem: types.reference(Item),
    items: types.array(Item)
  })
  .actions(self => ({
    selectItem(itemId: string) {
      self.selectedItem = itemId
    },
  }))

You need to:

const store = NotebookStore.create({
  items: [
    {id: '1', model: 'MacBook Pro', manufacturer: 'Apple'},
    {id: '2', model: 'ZenBook', manufacturer: 'Asus'}
  ],
  selectedItem: '1'
})

Here you put real items at items and _reference_ (by id) at selectedItem, so:

console.log(store.selectedItem) // yields {id: '1', model: 'MacBook Pro', manufacturer: 'Apple'}
// same as store.items[0]
store.selectItem('2');
console.log(store.selectedItem) // yields    {id: '2', model: 'ZenBook', manufacturer: 'Asus'}
// same as store.items[1]

If that's not what you're looking for, then I couldn't catch the idea behind the question.
BTW, you do not "assign" by identifier, but rather "change pointer".

If you want to use reference from another store, please refer to this coment for example

Thanks. Could be that comment is the issue.

Trying to assign the string to the reference at the moment was giving me this Typescript error:

Type 'string' is not assignable to type 'Pick; type: ISimpleType; id: ISimpleType; title: ISimpleType; author: ISimpleType

@xaviergonz , could you please advice on the TS error?
I assume one needs to use castToReferenceSnapshot to cover such scenario?

It may be the issue is to do with using different stores as the comment you linked to.

This issue has been automatically marked as stale because it has not had recent activity in the last 10 days. It will be closed in 4 days if no further activity occurs. Thank you for your contributions.

Assuming you have:

const Item = types.mode('Notebook', {
  id: types.identifier,
  model: types.string,
  manufacturer: types.string,
})
const NotebookStore = types.model('NotebookStore', {
    selectedItem: types.reference(Item),
    items: types.array(Item)
  })
  .actions(self => ({
    selectItem(itemId: string) {
      self.selectedItem = itemId
    },
  }))

You need to:

const store = NotebookStore.create({
  items: [
    {id: '1', model: 'MacBook Pro', manufacturer: 'Apple'},
    {id: '2', model: 'ZenBook', manufacturer: 'Asus'}
  ],
  selectedItem: '1'
})

Here you put real items at items and _reference_ (by id) at selectedItem, so:

console.log(store.selectedItem) // yields {id: '1', model: 'MacBook Pro', manufacturer: 'Apple'}
// same as store.items[0]
store.selectItem('2');
console.log(store.selectedItem) // yields    {id: '2', model: 'ZenBook', manufacturer: 'Asus'}
// same as store.items[1]

If that's not what you're looking for, then I couldn't catch the idea behind the question.
BTW, you do not "assign" by identifier, but rather "change pointer".

I have the same problem: I can't assign a string to a reference. In the example above: I get a ts-error in the selectItem action.

@xaviergonz can you reopen that please?

This issue has been automatically unmarked as stale. Please disregard previous warnings.

In the example above: I get a ts-error in the selectItem action.

Yeah, you need to do

self.selectedItem = itemId as any

when itemId is a string currently sadly

I actually want to write a RFC for a new way to use identifiers so they are more TS friendly, but sadly it would be a breaking change

something like

const M = types.model({ ref: types.reference(whateverType) })

const m = M.create({ ref: "123" })

m.ref.valid // true if the ref is not broken, false if it is broken

m.ref.get() // gets the object pointed at, throws if the ref is not valid
m.ref.getId() // gets the id the ref is pointing to

m.ref.set(obj | id) sets the ref to point to a given object (if obj) or to a given id (if string or number), throws if the given obj or id is invalid
// alternatively
m.ref.set(obj) + m.ref.setId(id)

Technically it could also be done by adding a new ref type (or actually two with safeReference), but that'd mean we'd end up with 4 possible ref types

This issue has been automatically marked as stale because it has not had recent activity in the last 10 days. It will be closed in 4 days if no further activity occurs. Thank you for your contributions.

Was this page helpful?
0 / 5 - 0 ratings