@theuiteam/continuous-container
v2.0.1
Published
State container with the known past, present, and the future
Downloads
5,793
Readme
Idea
This 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
ContinuousState
future
- the next value. The value you just set.present
- to be synchronized with thefuture
"later"past
- to be synchronized with thepresent
"later"
and
defined
- an indication that any of future, past or present are truthy.
API
useContinuousState(value, options)
value
- a value to assign to thefuture
options
delayPresent
- time in ms betweenfuture
becomingpresent
delayPast
- time in ms betweenpresent
becomingpast
. For transitions, it usually equals to exist animation durationinitialValue
- a value to be set as initial to thepast
andpresent
.future
is always equal to thevalue
given as a first arg
useScatteredContinuousState(value, options)
Call signature is equal to useContinuousState
, returns an object with extra property DefinePresent
. See example below.
Usage
Problem statement
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:
const App = () => {
const [on, setOn] = useState(false);
return (
<div>
<button onClick={() => setOn(on => !on)}>Toggle</button>
// would be instanly hidden and shown
{on && <Content/>}
// would be animated, but would be ALWAYS rendered
<ContentWithAnimation visible={on}/>}
</div>
);
};
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
import { ContinuousContainer, useContinuousState } from '@theuiteam/continuous-container';
const App = () => {
const [on, setOn] = useState(false);
const continuousState = useContinuousState(on);
return (
<div>
<button onClick={() => setOn((on) => !on)}>Toggle</button>
{/*render if any of past/preset/future is set to true*/}
{continuousState.defined && (
<ContentWithAnimation visible={continuousState.present} />
// wire the "present" state
)}
{/* or */}
<ContinuousContainer value={on} timeout={300}>
{
(past, present, future) => (past || present || future) && <ContentWithAnimation visible={present} />
// ^^ use the "present" value
}
</ContinuousContainer>
</div>
);
};
Scattered
There are more sophisticated situations, when setting up something to display does not mean "display". Lazy loading is a good case
const App = () => {
const continuousState = useContinuousState(on);
return continuousState.defined && <LazyLoadedContentWithAnimation visible={continuousState.present} />;
};
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
const continuousState = useScatteredContinuousState(on);
return (
continuousState.defined && (
<Suspense>
<LazyLoadedContentWithAnimation visible={continuousState.present}>
<continuousState.DefinePresent />
{/*this component will advance ContinuousState once rendered*/}
</LazyLoadedContentWithAnimation>
</Suspense>
)
);
For readability purposes we recommend putting DefinePresent to a separate slot different from children
.
<LazyLoadedContentWithAnimation visible={continuousState.present} effector={<continuousState.DefinePresent />} />
⚠️⚠️⚠️⚠️⚠️⚠️⚠️
The following code will NOT work as DefinePresent
will be rendered instantly, even if suspense will be in fallback
<Suspense>
// will not be rendred until ready
<LazyLoadedContentWithAnimation visible={continuousState.present} />
// will be rendered too early
<continuousState.DefinePresent />
</Suspense>
See also
- Phased Container from a
recondition
library
License
MIT