javascriptreactjsreact-loadable

How to get state via React-Loadable? React-Redux


I written a custom logic for handling async route loading bundles in react-router-dom .v4. It's work perfectly. But also I heard about useful package with nice API to do the same, like React-Loadable. It has one problem, I cannot get the props/state pushed from Redux on the mount of the component throw this package.

My code is rewritten from the custom style to react-loadable style in two examples below. The last one is react-loadable version, that does not throw state/props.

My personal code:

const asyncComponent = getComponent => {
  return class AsyncComponent extends React.Component {
    static Component = null;

    state = { Component: AsyncComponent.Component };

    componentWillMount() {
      const { Component } = this.state

      if (!Component) {
        getComponent().then(({ default: Component }) => {
          const { store } = this.props // CAN GET THE REDUX STORE

          AsyncComponent.Component = Component;
          this.setState({ Component });
        });
      }
    }

    render() {
      const { Component } = this.state;

      if (Component) {
        return <Component {...this.props} />
      }

      return null;
    }
  };
};

export default withRouter(asyncComponent(() => import(/* webpackChunkName: "chunk_1" */ './containers/Component')))

The same code, but with React-Loadable:

const Loading = () => {
  return <div>Loading...</div>;
}

const asyncComponent = Loadable({
  loader: () => import(/* webpackChunkName: "" */ './containers/Component')
    .then(state => {    
      const { store } = this.props // CANNOT GET THE REDUX STORE!!
    }),
  loading: Loading
})

export default withRouter(asyncComponent)

Solution

  • To get the state from Redux store via Provider you should place your asyncComponent in Stateful Component wrapper, like you do in your custom async logic (1st case).

    It because Loadable library returns you asyncComponent like a function, not a constructor, that way he cannot get access to current Redux store. So, the working solution will be the next:

    const Loading = () => {
      return <div>Loading...</div>;
    }
    
    const asyncComponent = Loadable({
      loader: () => import(/* webpackChunkName: "" */ './containers/Component')
        .then(state => {    
          const { store } = this.props // YOU WILL GET THE REDUX STORE!!
        }),
      loading: Loading
    })
    
    class asyncComponentWrapper extends Component{ // Component wrapper for asyncComponent
      render() {
        return <asyncComponent {...this.props} />
      }
    }
    
    export default withRouter(asyncComponentWrapper)
    

    P.S.

    I do not know what you try to do, but in case how to make reducer injection inside the current store (probably it's exactly what you trying to do), you need to include you Redux store explicitly by import, not from the Provider state.