Сочетание Mobx-state-tree, Mobx-реагировать и RenderProps не обновляет компонент реакции - PullRequest
0 голосов
/ 10 апреля 2019

Это сложная проблема. Надеюсь, мне удастся объяснить, чтобы каждый мог понять ошибку

1) Родительский компонент.

@observer
export class Edit extends React.Component<IProps> {
  article: any

  componentWillMount() {
    const articleId = this.props.routerStore!.routerState.params.id!

    this.article = ArticleModel.create({ id: articleId || null })
    this.article.init()
  }

  render() {
    if (!this.article) {
      return <div>loading...</div>
    }

    return <div className='main-wrapper'>
      <EditArticle article={this.article} />
    </div>
  }
}

2) Дочерний компонент Он использует react-beautiful-dnd, чтобы разрешить перетаскивание на макете статьи. Эта библиотека использует RenderProps (provided: any, snapshot)


@observer
export class EditArticle extends React.Component<IProps> {
  render() {
    return <div className='main-column article-target'>
      <Droppable
        ignoreContainerClipping
        direction={'vertical'}
        droppableId='article'
        key={'article'}
      >
        {(provided: any, snapshot: any) => {
          return <ObservedDragDropContext
              provided={provided}
              snapshot={snapshot}
            >
              {this.props.article.layout.map((el: any, index: number) => {
                return <WithDragable
                  key={getPath(el)}
                  id={getPath(el)}
                  index={index}
                  remove={() => {}}
                >
                  <div className='layout-item'>
                    <Layout key={getPath(el)} item={el} />
                  </div>
                </WithDragable>
              })}
            </ObservedDragDropContext>
        }}
      </Droppable>
    </div>
  }
}

Статья представляет собой модель дерева состояний mobx. Это метод init свойства actions модели:

init() {
  const run = flow(function*() {
    const res = yield getArticle(self.id)
    applySnapshot(self, res)
  })

  run()
},

Поток следующий: 1) создать статью 2) инициировать статью 3) Я ожидаю, что статья будет обновлена ​​после того, как я получу ответ и применюSnapshot к статье

Но дочерний компонент не перерисовывается после запуска applySnapshot. Я проверил и применилSnapshot работает, и статья имеет обновленные значения, полученные из бэкэнда

Полагаю, проблема в том, что я использую RenderProps в своем дочернем компоненте, и это каким-то образом мешает и запрещает повторную визуализацию компонента.

Хитрость в том, что если я добавлю

{this.props.article.layout.map((el: any, index: number) =>
  <Layout key={getPath(el)} item={el} />
)}

в дочернем компоненте функции render в любом месте, это решит проблему, и начальный компонент будет обновлен. Так что, просто перерисовав реквизиты, дочерний компонент переопределяет себя и неявно исправляет мою первоначальную ошибку, перерисовывая Drappable и RenderProps.

Возможное решение 1: , если я использую другую библиотеку реагирования DND, в которой не используется RenderProps, все обновляется, как и должно. Но я не хочу этого делать, потому что react-beautiful-dnd имеет хорошую анимацию, и мне нужно было бы реорганизовать часть кода.

Я не смог понять, почему дочерний компонент не перерисовывается.

Дочерний компонент не знает, что это зависит от статьи, потому что я использую this.props.article только внутри renderProps?

Можно ли избежать использования renderProps?

...