Retrofit your existing
unstated
container. Feels likeunstated-next
. Bridge the gap until you can swap.
unstated-next is great for new projects, but if you've been using unstated for awhile, you probably already have some containers that aren't quick to rewrite and replace.
This package seeks to bridge that gap via a "child-first" migration. You can start rewriting child components to use hooks, and then eventually rewrite your container in the style of unstated-next
. It aims to be API compatible with unstated-next
for a smooth migration from (unstated + retro) to pure unstated-next
.
unstated | unstated-next | unstated-retro | |
---|---|---|---|
Container | class CounterContainer extends Container |
let Container = createContainer(customHook) |
let RetroContainer = createRetroContainer(CounterContainer) |
Provider | <Provider> |
<Container.Provider> |
<RetroContainer.Provider> |
Subscribe | <Subscribe> |
Container.useContainer() |
RetroContainer.useContainer() |
Tunnel | - | - | <RetroContainer.Tunnel> |
React Version | ^15.0 |
^16.8 |
^16.8 |
The way to inject containers in unstated-retro
matches the style of unstated-next
.
unstated | unstated-next | unstated-retro | |
---|---|---|---|
What is provided | Any Container class |
The customHook passed to createContainer |
The Container passed to createRetroContainer |
Inject an instance | <Provider inject={[instance]}> docs |
- | createContainer(instance) |
npm install --save unstated-retro
import React, { useState } from "react"
import { render } from "react-dom"
import { Container } from 'unstated';
import { createRetroContainer } from "unstated-retro"
type CounterState = {
count: number,
}
class CounterContainer extends Container<CounterState> {
state = {
count: 0,
}
increment() {
this.setState({ count: this.state.count + 1 })
}
decrement() {
this.setState({ count: this.state.count - 1 })
}
}
let RetroContainer = createRetroContainer(CounterContainer)
function CounterDisplay() {
let counter = RetroContainer.useContainer()
return (
<div>
<button onClick={counter.decrement}>-</button>
<span>{counter.count}</span>
<button onClick={counter.increment}>+</button>
</div>
)
}
function App() {
return (
<RetroContainer.Provider>
<CounterDisplay />
<CounterDisplay />
</RetroContainer.Provider>
)
}
render(<App />, document.getElementById("root"))
class CounterContainer extends Container<CounterState> {
state = {
count: 0,
}
increment() {
this.setState({ count: this.state.count + 1 })
}
decrement() {
this.setState({ count: this.state.count - 1 })
}
}
let RetroContainer = createRetroContainer(CounterContainer)
// RetroContainer === { Provider, Tunnel, useContainer }
function ChildComponent() {
let input = RetroContainer.useContainer()
return <input value={input.value} onChange={input.onChange} />
}
useContainer
is designed to match the style of unstated-next
let RetroContainer = createRetroContainer(CounterContainer)
// RetroContainer === { Provider, Tunnel, useContainer }
function ParentComponent() {
return (
<Provider>
<RetroContainer.Tunnel>
<CounterDisplay />
<CounterDisplay />
</RetroContainer.Tunnel>
<CounterDisplay />
</Provider>
)
}
Bridges the context from a wrapper Provider
via a Tunnel
to a child using useContainer
function ParentComponent() {
return (
<RetroContainer.Provider>
<CounterDisplay />
</RetroContainer.Provider>
)
}
Replaces <Provider/>
from unstated
.
const counter = new CounterContainer(); // Global instance
let RetroContainer = createRetroContainer(counter)
// RetroContainer === { Provider, Tunnel, useContainer }
function ParentComponent() {
return (
<RetroContainer.Provider>
<CounterDisplay />
</RetroContainer.Provider>
)
}
I need new shared state using an existing container
Use <RetroContainer.Provider>
from unstated-retro
in your new parent components, and useContainer
in your new child components.
I am building a new child component
Use <RetroContainer.Tunnel>
from unstated-retro
in your existing parent components, and useContainer
in your new child components.
I want to slowly migrate
- Use
unstated-retro
- Create a
RetroContainer
withcreateRetroContainer(LegacyContainer)
- Add
<RetroContainer.Tunnel>
fromunstated-retro
in your existing parent components
- Create a
- Start writing new child components using
useContainer
. - Replace
<Subscribe/>
- Migrate existing child components from
<Subscribe/>
touseContainer
.
- Migrate existing child components from
- Replace
<Provider/>
- Confirm all child components use
useContainer
instead of<Subscribe/>
- Swap from
<Provider><RetroContainer.Tunnel>
to just<RetroContainer.Provider>
- Confirm all child components use
- Migrate to
unstated-next
- Confirm all parent components use
<RetroContainer.Provider>
instead of<Provider>
- Rewrite your
LegacyContainer
as a hook - Switch from
createRetroContainer
tocreateContainer
- Confirm all parent components use
I'm building something completely new
Don't use this library, use unstated-next
. Celebrate that you're not bogged down by supporting legacy unstated
containers.