State container with the known past, present, and the future
npm install @theuiteam/continuous-containeruseState aware of continuous nature of timeThis is almost react transition group, but for state management...
Why people react transition group? Because it 1) takes a pause
between steps letting classNames be applied and 2) keeps children after you remove them, to perform a fade
animation.
We are doing the same, but using state.
It's all about tracking what the value would be, what is right now, and what it was.
We call this ContinuousState
- future - the next value. The value you just set.
- present - to be synchronized with the future "later"
- past - to be synchronized with the present "later"
and
- defined - an indication that any of future, past or present are truthy.
- value - a value to assign to the future
- options
- delayPresent - time in ms between future becoming present
- delayPast - time in ms between present becoming past. For transitions, it usually equals to exist animation duration
- initialValue - a value to be set as initial to the past and present. future is always equal to the value given as a first arg
Call signature is equal to useContinuousState, returns an object with extra property DefinePresent. See example below.
Let's imagine you have a switch. Which controls visibility of something, but you also want to add some animation.
Let's handle these cases separately:
``typescript jsx
const App = () => {
const [on, setOn] = useState(false);
return (
Now let's imagine you want to not render Content _when_ it's not visible and not required.
Ok, "when is this _when_"?
- render
ContentWithAnimation when it is _about_ to be displayed
- render ContentWithAnimation when it is displayed
- render ContentWithAnimation when it is no longer visible, but still animating toward hidden state`typescript jsx
import { ContinuousContainer, useContinuousState } from '@theuiteam/continuous-container';const App = () => {
const [on, setOn] = useState(false);
const continuousState = useContinuousState(on);
return (
{/render if any of past/preset/future is set to true/}
{continuousState.defined && (
// wire the "present" state
)}
{/ or /}
{
(past, present, future) => (past || present || future) &&
// ^^ use the "present" value
}
);
};
`Scattered
There are more sophisticated situations, when setting up something to display does not mean "display". Lazy loading
is a good case
`tsx
const App = () => {
const continuousState = useContinuousState(on);
return continuousState.defined && ;
};
`In such case ContinuousState will update from
future to present before LazyLoadedContentWithAnimation component is
loaded, breaking a connection between states.In order to handle this problem one might need to _tap_ into rendering process using
useScatteredContinuousState`tsx
const continuousState = useScatteredContinuousState(on);
return (
continuousState.defined && (
{/this component will advance ContinuousState once rendered/}
)
);
`For readability purposes we recommend putting DefinePresent to a separate slot different from
children.`tsx
} />
`###### ⚠️⚠️⚠️⚠️⚠️⚠️⚠️
The following code will NOT work as
DefinePresent will be rendered instantly, even if suspense will be in fallback`tsx
// will not be rendred until ready
// will be rendered too early
`See also
- Phased Container from a
recondition` libraryMIT