Migration From react-relink
info
The usage of .get
, .set
, .reset
, and .dispose
remains the same.
Setup
Before
yarn add react-relink
Now
yarn add cotton-box cotton-box-react
Instantiation
Before
import { RelinkSource } from 'react-relink'
const ExampleSource = new RelinkSource({
key: 'example-source',
default: 'defaultState',
lifecycle: {
init({ commit, commitNoop, defaultState }) {
// ...
},
didSet({ state }) {
// ...
},
didReset() {
// ...
},
},
options: {
suspense: true | false,
public: true | false,
},
scope: OtherSource,
})
Now
import { AsyncStateManager, StateManagerVisibility } from 'cotton-box'
// Default state is passed as first parameter,
// remaining options are passed as the second.
const ExampleState = new AsyncStateManager('defaultState', {
// `key` is no longer needed, but there is a `name` property,
// which is *optional* and only used for debugging.
lifecycle: {
init({ commit, commitNoop, defaultState }) {
// ...
},
// `defaultState` is exposed here:
didSet({ state, defaultState }) {
// ...
},
didReset() {
// ...
},
},
// New option:
clientOnly: true | false,
// `visibility` is a boolean type in react-relink:
visibility: StateManagerVisibility.ENVIRONMENT,
suspense: true | false,
scope: OtherState,
})
Consuming the State
Before
function App() {
import { useRelinkValue } from 'react-relink'
const state = useRelinkValue(ExampleSource)
return '...'
}
Now
function App() {
import { useStateValue } from 'cotton-box-react'
const state = useStateValue(ExampleState)
return '...'
}
Handling dependencies
Before
const ExampleSourceA = new RelinkSource({
key: 'example-source-a',
default: '...',
lifecycle: { /* ... */ },
})
const ExampleSourceB = new RelinkSource({
key: 'example-source-b',
default: '...',
deps: [ExampleSourceA],
lifecycle: { /* ... */ },
})
Now
const ExampleStateA = new StateManager('...')
const ExampleStateB = new StateManager('...', {
lifecycle: {
init() {
await ExampleStateA.isInitializing.wait(false)
// continue to do something
},
},
})
Re-initialization
Before
MySource.hydrate(...)
Now
ExampleState.init(...)
Scope
Before
const ExampleSourceA = new RelinkSource({
key: 'example-source-a',
default: '...',
})
const ExampleSourceB = new RelinkSource({
key: 'example-source-b',
default: '...',
scope: ExampleSourceA,
})
function App() {
return (
<RelinkScope with={[ExampleSourceB]}>
<MyComponent />
</RelinkScope>
)
}
function MyComponent() {
const [state, setState, resetState] = useRelinkState(ExampleSourceB)
return '...'
}
Now
const ExampleStateA = new StateManager('...')
const ExampleStateB = new StateManager('...', {
scope: ExampleStateA,
})
function App() {
return (
<StateManagerScopeProvider with={[ExampleStateB]}>
<MyComponent />
</StateManagerScopeProvider>
)
}
function MyComponent() {
const state = useStateValue(useScoped(ExampleStateB))
return '...'
}