unstated-retro
v1.0.0
Published
615 bytes to bridge the gap from unstated to unstated-next
Downloads
4
Maintainers
Keywords
Readme
Unstated Retro
Retrofit your existing
unstated
container. Feels likeunstated-next
. Bridge the gap until you can swap.
Motivation
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
.
Comparison to unstated
and 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)
|
Install
npm install --save unstated-retro
Example
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"))
API
createRetroContainer(ContainerOrInstance)
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 }
Container.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
<Container.Tunnel>
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
<Container.Provider>
function ParentComponent() {
return (
<RetroContainer.Provider>
<CounterDisplay />
</RetroContainer.Provider>
)
}
Replaces <Provider/>
from unstated
.
<Container.Provider>
injected instance
const counter = new CounterContainer(); // Global instance
let RetroContainer = createRetroContainer(counter)
// RetroContainer === { Provider, Tunnel, useContainer }
function ParentComponent() {
return (
<RetroContainer.Provider>
<CounterDisplay />
</RetroContainer.Provider>
)
}
How do I use an existing unstated
container?
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 `
- 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.