Как сделать дочерний компонент реактивным на изменение состояния в mobx с помощью mobx-react-lite - PullRequest
1 голос
/ 28 мая 2020

Я использую mobx-state-tree и mobx-react-lite, может ли кто-нибудь подсказать мне лучший шаблон,

список желаний. js - хранилище списков желаний

import { types } from 'mobx-state-tree'

export const WishListItem = types.model('WishListItem', {
  name: types.string,
  price: types.number,
  image: "",
}).actions(self => ({
  changeName(newName) {
    self.name = newName
  },
}))

export const WishList = types.model('WishList', {
  items: types.optional(types.array(WishListItem), []),
})

root. js - root магазин

export const RootStore = types.model('RootStore', {
  counter: types.optional(Counter, { count: 0 }),
  wishList: types.optional(WishList, {
    items: [{ image: '', price: 10, name: 'Yoda' }]
  }),
})

Я обновляю магазин как

setInterval(() => store.wishList.items[0].changePrice(Math.random() * 100), 500)

В моем списке желаний просматривайте wishlist.jsx

const WishListItem = ({ image, name, price }) => {
  return useObserver(
    () =>
      <div>
        <img src={image} />
        <h3>{name}</h3>
        <h5>{price}</h5>
      </div>
  )
}

const WishListView = ({ items }) => {
  return useObserver(
    () => <>
      {
        items.map(
          (item, key) => <WishListItem {...item} key={key} />
        )
      }
    </>
  )
}

export default () => useObserver(() => (
  <WishListView items={store.wishList.items} />
))

Здесь я должен использовать useObserver или Observer на каждом уровне дерева компонентов, чтобы сделать его реактивным, есть ли способ передать реактивную ссылку дочернему элементу?

Это работает отлично работает с примитивными типами, такими как строка или число, но с массивом или объектом я должен либо напрямую ссылаться на изменяющиеся переменные в родительском элементе, например store.wishList[0].price, либо использовать useObserver во всем дереве.

Я хочу передать массив элементов дочерним элементам и обновить дочерние элементы при изменениях, только это root

export default () => useObserver(() => (
  <WishListView items={store.wishList.items} />
))

и больше не использовать useObserver на его дочерних элементах

Обновление

Обходной путь, который я нашел, заключался в деструктуризации массива, теперь изменения являются реактивными, так как мы получаем прямой доступ к изменяющимся переменным.

export default () => useObserver(() => {
  const items = store.wishList.items.map(item => ({ ...item }))
  return <WishListView items={items} />
})

1 Ответ

1 голос
/ 10 июня 2020

и больше никакого useObserver на его дочерних элементах

На самом деле лучше пометить все компоненты как observer, если это возможно. Например, если вы пометите каждый Item как наблюдатель, и один из элементов изменит свое имя, то только этот компонент будет повторно отображен. Если вы не сделаете Item наблюдателем, тогда весь ваш List будет перерисован, что довольно плохо, если у вас много элементов или глубокое дерево DOM. Также не имеет смысла повторно отображать весь список, когда изменяется только один элемент.

Смотрите здесь объяснение https://mobx.js.org/refguide/observer-component.html#when -to-apply-Observer

Итак, ваш обходной путь - плохая практика и должна использоваться только в крайнем случае, если вы не контролируете дочерние компоненты и не можете их создавать observer.

...