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

multiple containers - Provider Inject #35

Closed
neckaros opened this issue Jun 9, 2019 · 3 comments
Closed

multiple containers - Provider Inject #35

neckaros opened this issue Jun 9, 2019 · 3 comments

Comments

@neckaros
Copy link

neckaros commented Jun 9, 2019

What is the recommanded way to have multiple containers provided to our App?
in unstated you could use dependency injection:

<Provider inject={[container1, container2...]}>
 MyApp...
<Provider>

but it seems that with next the only way in a tree hell:

<Container1.Provider>
   <Container2.Provider>
     MyApp
   </Container2.Provider>
</Container1.Provider>

Am i missing something?

@jamiebuilds
Copy link
Owner

My advice is to avoid putting everything at the top-level of your app unless it actually needs to be there.

But if this is actually a problem, you can do this:

function compose(...containers) {
  return function Component(props) {
    return containers.reduceRight((children, Container) => {
      return <Container.Provider>{children}</Container.Provider>
    }, props.children)
  }
}

Of course this still produces a fairly large tree. But I don't want to build anything more complex in, and until/unless React gives us a useProvider(...) or a way to provide multiple contexts at once, that problem is gonna stick around.

@neckaros
Copy link
Author

makes sense.
Thanks !

@Dreamacro
Copy link

Dreamacro commented Jul 4, 2019

To me, I write a helper function to merge containers

type containerFn<Value, State = void> = (initialState?: State) => Value

export function composeContainer<T, C = containerFn<T>, U = { [key: string]: C }> (mapping: U) {
    function Global () {
        return Object.keys(mapping).reduce((obj, key) => {
            obj[key] = mapping[key]()
            return obj
        }, {}) as { [K in keyof U]: T }
    }

    const globalContainer = createContainer(Global)
    return {
        Provider: globalContainer.Provider,
        containers: Object.keys(mapping).reduce((obj, key) => {
            obj[key] = function () {
                return globalContainer.useContainer()[key]
            }
            return obj
        }, {}) as { [K in keyof U]: U[K] }
    }
}

How to use:

// store.ts
function useCounter(initialState = 0) {
    const [count, setCount] = useState(initialState)
    const decrement = () => setCount(count - 1)
    const increment = () => setCount(count + 1)
    return { count, decrement, increment }
}

function useAnotherCounter(initialState = 0) {
    const [count, setCount] = useState(initialState)
    const decrement = () => setCount(count - 1)
    const increment = () => setCount(count + 1)
    return { count, decrement, increment }
}

const { Provider, containers } = composeContainer({
    useCounter,
    useAnotherCounter
})

export { Provider, containers }
// app.tsx
import { Provider as Global, containers } from './store'
function renderApp () {
    const rootEl = document.getElementById('root')
    const AppInstance = (
        <Global>
            <App />
        </Global>
    )
    render(AppInstance, rootEl)
}

function App () {
    const { count } = container.useCount()
    return (
        <div>{ count }</div>
    )
}

Repository owner deleted a comment from csr632 Mar 17, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants