Skip to main content

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 '...'
}