MobX + React让我发疯

时间:2017-11-16 19:54:30

标签: javascript mobx mobx-react

首先,我没有经验的React开发人员。只是让你知道。

我有一家商店:

import {observable, action, reaction, computed, autorun} from 'mobx';
import scrollTo from 'react-scroll-to-component'

类ActivePostsStore {

  @observable _posts = new Map()
  @observable _visiblePosts = new Set()

  @computed get visiblePosts() {
    return this._visiblePosts
  }

  @action
  addPost(uuid, ref) {
    // console.log('add post')
    this._posts.set(uuid, ref)
  }

  @action
  scrollToPost(uuid) {
    // console.log('scroll to post')
    scrollTo(this._posts.get(uuid), {})
  }

  @action
  addVisiblePost(uuid) {
    console.log('add vis post', this._visiblePosts.values())
    this._visiblePosts.add(uuid)
  }

  @action
  removeVisiblePost(uuid) {
    console.log('rem vis post', this._visiblePosts.values())
    this._visiblePosts = new Set([...this._visiblePosts].filter(el => el !== uuid))
  }

  // reacts = reaction(() => this._visiblePosts, () => console.log('===='))
  // reactToVisiblePosts() {
  //
  // }
}


const store = new ActivePostsStore()
export default store

我的第一个问题是,我可以通过我的布局组件或_document.js中的Provider传递商店(我使用Next.js)。

/*Doesn't work. In root layout*/
<Provider store={ActivePostsStore}>
  <Content />
</Provider>

每当我尝试使用Provider时,我的商店都未定义。在RootLayout或_document.js中也是如此。当然,我为使用商店的组件提供了@observer注释。但商店仍未定义。

然后,我尝试使用@inject('activePostsStore')结果是错误,这告诉我,就像我根本没有提供任何商店。但是,实际上,我做到了。

SO!我决定直接注射它:

@inject(() => ({
  store: ActivePostsStore
}))
@observer

最后,我可以使用操作来添加或删除visiblePosts的元素(我记录它)。但!如果我改变商店的状态,我的商店道具根本没有反应。例如,它不会对向visiblePosts添加新条目做出反应。或者,如果我重新加载页面,它甚至可以是未定义的。我的组件代码是:

render() {
    const {classes} = this.props
    return (
      <div className={classNames(classes.postsTree)}>
        {this.props.store.visiblePosts}
        {this.state.groupedDates !== undefined && this.state.groupedDates.map(([date, posts], index) =>
          <PostsTreeGroup
            active={_.some(posts.map(([uuid]) => uuid), uuid => this.props.store.visiblePosts.has(uuid))}
            key={date}
            date={date}
            posts={posts}/>
        )}
      </div>
    )
  }

请有人帮助我让事情有效!

2 个答案:

答案 0 :(得分:4)

<强>问题1:

提供程序仅在您在组件上调用注入时才有效,您希望商店出现在其道具中。所以你必须调用inject,否则商店是未定义的(因为没有人为你的商店设置组件的属性)。

您传递给inject的字符串必须是您在Provider中提供的属性名称。

你有:

<Provider store={ActivePostsStore}> // store is the property name

所以你也必须打电话

@inject('store')

然后mobx会查找密钥存储区,在您的提供程序中找到它并将其分配给您的组件。

<强>问题2:

您可以计算商店中的可见帖子,而不是相反。 所以方法visiblePosts只返回可见的帖子。

商店:

@computed get visiblePosts() {
  return this._visiblePosts.map(uuid => this._posts.get(uuid));
}

然后在您的组件中,您只能渲染可见的帖子:

组件:

this.props.store.visiblePosts.map(post => {
 return <PostsTreeGroup ...>
})

我也看到你做某种排序?

然后,您可以告诉您的商店如何排序(例如设置属性),然后让您的商店在visiblePosts方法中进行排序。

答案 1 :(得分:3)

小补充:乍一看,您正在将传递给提供程序,而不是实例ActivePostsStore)。确保实例化您的类,以便您可以使用实际的商店。 (如果你确实创建了一个实例,那么最好坚持使用小写的第一个字母)