Это сложная проблема. Надеюсь, мне удастся объяснить, чтобы каждый мог понять ошибку
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?