首页 文章

使用React Loadable在HOC中包含的代码拆分路径组件

提问于
浏览
0

我正在使用React Loadable使用Webpack 3.11进行基于路由的代码拆分时遇到问题 .

当我尝试在服务器上呈现我的应用程序时,我的异步模块会立即解析而无需等待承诺 . 因此SSR输出变为 <div id="root"></div> .

App.js:

const App = () => (
  <Switch>
    {routes.map((route, index) => (
      <Route key={index} path={route.path} render={routeProps => {
        const RouteComponent = route.component
        return <RouteComponent {...routeProps} />
      }} />
    ))}
  </Switch>
)

我用React Loadable定义了我的异步路由组件,如下所示:

Routes.js

function Loading ({ error }) {
  if (error) {
    return 'Oh nooess!'
  } else {
    return <h3>Loading...</h3>
  }
}

const Article = Loadable({
  loader: () => import(/* webpackChunkName: "Article" */ '../components/contentTypes/Article'),
  loading: Loading
})

const Page = Loadable({
  loader: () => import(/* webpackChunkName: "Page" */ '../components/contentTypes/Page'),
  loading: Loading,
  render (loaded, props) {
    let Component = WithSettings(loaded.default)
    return <Component {...props}/>
  }
})

export default [
  {
    path: `/:projectSlug/:env${getEnvironments()}/article/:articleSlug`,
    component: Article,
    exact: true
  },
  {
    path: `/:projectSlug/:env${getEnvironments()}/:menuSlug?/:pageSlug?`,
    component: Page
  }
]

WithSettings.js

export default (WrappedComponent: any) => {
  class WithSettings extends React.Component<WithSettingsProps, WithSettingsState> {
    static displayName = `WithSettings(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`

    state = {
      renderWidth: 1200
    }

    componentDidMount () {
      this.loadSettings({ match: { params: { projectSlug: '', env: '' } } })
      window.addEventListener('resize', this.onResize)
      this.onResize()
    }

    componentWillUnmount () {
      if (isClient) {
        window.removeEventListener('resize', this.onResize)
      }
    }

    componentDidUpdate (oldProps) {
      this.loadSettings(oldProps)
    }

    onResize = () => {
      this.setState({ renderWidth: this.getLayoutWidth() })
    }

    getLayoutWidth () {
      return (document.body && document.body.offsetWidth) || 0
    }

    loadSettings (oldProps) {
      const { settings, request, getNewSettings } = this.props
      const { projectSlug: oldProjectSlug, env: oldEnv } = oldProps.match.params
      const { projectSlug: newProjectSlug, env: newEnv } = this.props.match.params

      if (
        (
          oldProjectSlug !== newProjectSlug ||
          oldEnv !== newEnv
        ) ||
        (
          settings === undefined ||
          (request.networkStatus === 'ready')
        )
      ) {
        getNewSettings()
      }
    }

    render () {
      const { settings, request, history, location, match } = this.props
      const { renderWidth } = this.state

      if (!settings || !request || request.networkStatus === 'loading') {
        return <div />
      }

      if (request.networkStatus === 'failed') {
        return <ErrorBlock {...getErrorMessages(match.params, 'settings')[4044]} fullscreen match={match} />
      }

      return (
        <WrappedComponent
          settings={settings}
          settingsRequest={request}
          history={history}
          location={location}
          match={match}
          renderWidth={renderWidth}
        />
      )
    }
  }

  hoistNonReactStatic(WithSettings, WrappedComponent)

  return connect(mapStateToProps, mapDispatchToProps)(WithSettings)
}

我已经设法将其缩小到我用来包装我的路由组件的 WithSettings HOC . 如果我不使用 WithSettings HOC(与Article路由一样),那么我的SSR输出等待异步导入完成,服务器生成的html包含与路由相关的标记(好!) . 如果我使用HOC(与Page route一样),那么模块会立即解析并且我的SSR输出变为 <div id="root"></div ,因为它在渲染之前不再等待动态导入完成 . 问题是:我需要在所有路由中使用WithSettings HOC,因为它从我需要呈现应用程序的服务器获取所需数据 .

任何人都可以告诉我如何使用HOC并使用React Loadable的路由组件的异步组件,以便它在服务器上工作?

1 回答

  • 0

    管理好弄清楚 .

    这是由于我的HOC . 在render方法中,当 settingsrequest 未定义或 request.networkStatusloading 时,它将返回 <div /> . 事实证明,这会导致服务器端渲染 . 删除此块足以使其工作 .

相关问题