Add support for loading multiple imports per component (localization) · Issue #23 · ctrlplusb/react-async-component · GitHub
Skip to content

Add support for loading multiple imports per component (localization) #23

Open

Description

@swernerx

I'd like to see support for loading locale-specific i18n message files together with the actual view component. This would allow for route-splitted translation files which, as the view itself, are just loaded on demand e.g. for usage with IntlProvider by react-intl.

Conceptually it might look like:

const AboutView = createLazyComponent({
  load: (language) => {
    return [
      import("./views/About"),
      import("./views/About." + language + ".json")
    ]
  }
})

but int theory instead of an array we could also use an object/dict for being more specific:

const AboutView = createLazyComponent({
  load: (language) => {
    return {
      view: import("./views/About"),
      messages: import("./views/About." + language + ".json")
    }
  }
})

If there are messages it would probably be a good idea to use IntlProvider with the messages given for wrapping the dynamically loaded view. It might be also cool to use injectIntl for offering the intl API via props to the loaded view.

What do you think?

Activity

  1. changed the title [-]Add support for loading multiple imports per component[/-] [+]Add support for loading multiple imports per component (localization)[/+] on Mar 21, 2017
  2. swernerx commented on Mar 21, 2017

    @swernerx
    Author

    I tried implementing these requirements in style of your component in this file:
    https://github.com/sebastian-software/edgestack/blob/master/src/api/common/createLazyComponent.js

    But I would like working on a single solution instead of implementing too many alternatives.

  3. ctrlplusb commented on Apr 3, 2017

    @ctrlplusb
    Owner

    Hey @swernerx

    Thanks for this suggestion.

    With the latest code parse I did a bit of renaming to help the API move towards supporting something like your request.

    My initial idea is to allow an additional prop to be provided to an async component instance. Specifically a render callback function. The render callback would then receive the result of the render. Something like:

    const AboutView = asyncComponent({
      resolve: (props) => {
        const { language } = props
        return Promise.all([
          import("./views/About"),
          import("./views/About." + language + ".json")
       ])
      },
      passThroughProps: ['language']
    })
    
    <AboutView
      language="de"
      render={(resolved) => {
        const [ View, translations ] = resolved
        return <View translations={translations} />
      }}
    />

    The props pass through to the resolver poses an interesting question though. This would affect our caching. We would have to cache a result per variation of prop. Therefore we may need to consider adding an additional configuration value to asyncComponent called something like passThroughProps that would allow you define which props to pass to asyncComponent. These props would then be used as keys in a cache map of sorts.

    Thoughts?

  4. swernerx commented on Apr 4, 2017

    @swernerx
    Author

    Looks good.

    I just figure it would be nicer from the API standpoint to use named parameters/fields instead of array indexes and destructing. In this case we can't use Promise.all() as this does not work for objects... but it would be nicer from the usage standpoint. We could just return an objet in resolve() with { view: xx, translations: xx } and let the promise handling being done inside of asyncComponent.

    I wonder what's the benefit of making the pass-through config required? Why not just pass-through all props?

  5. djeeg commented on Apr 11, 2017

    @djeeg

    Perfect,

    I want to try something like this

    <Switch>
    	<Route path="/section1" render={(props) => (
    		<Layout store={this.context.store} {...props} />
    	)} />
    </Switch>
    
    const Layout = asyncComponent({
        resolve: (props) => {
            return Promise.all([
                System.import('./LayoutAsync'),
                System.import('./../logic/section1')
            ]).then(function([component, module]) {
                injectReducer(props.store, {key: 'section1State', reducer: module.reducer});
                injectSagas(props.store, module.SagasList);
                return component;
            })
        }
    });
    
  6. hoschi commented on Apr 26, 2017

    @hoschi

    interesting, a lot of people solving the same problem :)
    I did a prototype here https://github.com/hoschi/react-async-component/tree/feature/render

    Here is an example usage:

    import React from 'react';
    import GeneralIcon from 'place/GeneralIcon'
    import { asyncComponent } from 'react-async-component';
    
    export let config = {
        resolve: (props) => import( /* webpackChunkName: "dynamic-icons" */ `icons/${props.iconName}/iconDescription`),
        getModuleId: (props) => props.iconName,
        autoResolveES2015Default: false,
        render: (iconDescription, props) => <GeneralIcon {...props} iconDescription={ iconDescription } />,
    };
    
    export default asyncComponent(config);

    This can be used to

    • apply module content to a generic component
    • bundling each file in a directory as its own bundle and decide at runtime by props which to show
    • loading one module which contain different parts of the app, like @djeeg showed

    As my use case is a bit different, I create another ticket this or next week.

  7. hoschi commented on May 9, 2017

    @hoschi

    I created issue #44 for my use case

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions