Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for React's context API for non-static containers #785

Open
ghost opened this issue Feb 4, 2018 · 0 comments
Open

Support for React's context API for non-static containers #785

ghost opened this issue Feb 4, 2018 · 0 comments

Comments

@ghost
Copy link

ghost commented Feb 4, 2018

Hi, me again 😅 I'm creating an issue related to issue #595, but this time the solution you proposed won't work. I'll try to keep it simple and concise. The core of the issue is that I'm creating a React UI framework which really does not allow to make use of inversify-inject-decorators nor the solution you proposed in #595, because there might be many independant instances running at the same time.

Expected Behavior

import { injectable, inject, Container, ContainerProvider } from "inversify"

import MyKatana from "./MyKatana"

class MyLibaryProvider extends React.Component {
  
  container = new Container();

  constructor(props, context) {
    super(props, context);
    // configure the container here ....
    // in the real world, configuration could even depends on some
    // of the props passed to <MyLibraryProvider />
    this.container.bind<Katana>(Types.ComponentRegistry).to(MyKatana);
  } 

  render() {
    const { children } = this.props;
    return <ContainerProvider container={this.container}>
      {children}
    </ContainerProvider>
  }

}

@injectable()
class MyComponent extends  #React.Component  {

  // this now works, without having specified the container upfront!
  @inject(Types.Katana)
  katana: Katana
  
  render() {
     return <div>Foo!</div>
   }
}

Current Behavior

As far as I know, inversify only allows specifying one static container in combination with inversify-inject-decorators. Like I said, for libraries that might be used multiple times this option is not possible.

Possible Solution

A new React component, named ContainerProvider, with a definition similar to the following:

export class ContainerProvider extends React.Component<ContainerProviderProps, {}> {
  
  static childContextTypes = {
    container: PropTypes.object
  }

  getChildContext() {
    return {
      container: this.props.container
    }
  }

  render() {
    const { children } = this.props;
    return <React.Fragment>{children}</React.Fragment>;
  } 

}

A more advanced implementation might allow multiple containers to be passed to its children using different keys, but that would require a separate InversifyContainerStore.

Then, the @Injectable annotation could create a so-called 'React HoC' that would fetch the context that was passed to it via <ContainerProvider />

function injectable(Component) {

  return class extends React.Component<...> {

     static contextTypes = {
       container: PropTypes.object
     }

     render() {
       // createProxy has to be some Inversify internal ... I'm not very acquainted with the API
       const ProxiedComponent = createProxy(Component, this.context.container)
       return <ProxiedComponent {...this.props} />
     }

   }

}

That's about it. It might look ugly, but that old AntidoteJS project I created demonstrated that it is possible. I would be happy to integrate this in InversifyJS, but I'd really need some pointers as I know nothing of the internal API.

Context

I'm currently developing a UI library that makes extensive use of React's context API, which isn't recommended by the React developers. Now that the library is starting to get shape, I'm thinking of ways to make the code more stable and robust.

To be more generic, I think it would be a great addition to InversifyJS if React UI framework developers could make use of InversifyJS instead of relying on the experimental context API. Should the context API ever be replaced, developers would only need to update their InversifyJS version and that's it. Besides, the code looks more professional 😉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: No status
Development

No branches or pull requests

0 participants