React上下文更新不会导致组件重新呈现

时间:2018-05-15 03:36:07

标签: reactjs code-splitting code-splitting-async

我正在使用react路由器,webpack和动态导入为react app创建代码分割解决方案。我们的想法是将所有路由和相应的组件映射到不同的应用程序上下文,并根据应用程序上下文分割代码。当用户访问某个路由时,正在加载相关应用程序上下文的整个代码块。

代码示例:

App.tsx:

class App extends React.Component<Props, State> {
  render() {    
    if (this.props.data.loading || this.props.localData.loading) {
      return <Loader />
    }

    return (
      <IntlProvider locale={this.props.localData.session.locale} messages={this.state.translations}>
        <Router history={history}>
            <Route
              exact
              path={`/screens/:action?`}
              render={() => <ComponentLoader contextName={Context.Screens} componentName={'ScreenList'} />}
            />
        </Router>
      </IntlProvider>
    )
  }
}

export default withData(App)

ComponentLoader.tsx:

export enum Context {
  Screens = 'Screens',
  Channels = 'Channels'
}

const CONTEXT_LOADERS: { [name: string]: ComponentChunkLoader } = {
  [Context.Screens]: () => import('../../routerContexts/screens'),
  [Context.Channels]: () => import('../../routerContexts/channels'),
}

const loadedContexts: ContextsCollection = {}

class ComponentLoader extends React.PureComponent<Props, State> {

  state: State = {
    Component: null
  }

  async componentDidMount() {
    this._updateComponent(this.props)
  }

  async componentDidUpdate(prevProps: Props, prevState: State) {
    if (this.props.componentName !== prevProps.componentName || this.props.contextName !== prevProps.contextName) {
      this._updateComponent(this.props)
    }
  }

  _updateComponent = async (props: Props) => {
    let module = loadedContexts[props.contextName]
      ? loadedContexts[props.contextName]
      : await CONTEXT_LOADERS[props.contextName]()

    if (!loadedContexts[props.contextName]) loadedContexts[props.contextName] = module

    let ComponentClass = module[props.componentName]

    this.setState({
      Component: ComponentClass
    })
  }

  render() {

    if (this.state.Component !== null) {
      return <this.state.Component />
    }

    return <Loader />
  }
}

export default ComponentLoader

因此,当我切换到不同的路由时,我会正确地看到所有组件,并且代码分割正常工作。

问题是:当响应上下文更新中的数据时,示例中的ScreenList组件不会更新。当我直接将ScreenList传递给路由器Route时,一切正常。所以问题出在我用于代码拆分的ComponentLoader组件中。

任何想法可能是什么原因?

更新 Alrite,我现在想出来的:如果我将ComponentLoader包装在从上下文中注入一些数据的HOC(如export default withRouter(ComponentLoader))中,一切运行良好,组件按预期重新渲染。为什么会这样?

0 个答案:

没有答案