Skip to content

Commit

Permalink
Improve stories
Browse files Browse the repository at this point in the history
  • Loading branch information
spautz committed Feb 28, 2020
1 parent 94ca50a commit ac0d1b1
Show file tree
Hide file tree
Showing 11 changed files with 406 additions and 294 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -93,7 +93,7 @@ Read more: [@TODO: move most of this section to docs]
- [x] Proof of concept
- [x] Project scaffolding
- [x] Core functionality
- [ ] Tests
- [ ] Tests <-- in progress
- [x] Demos
- [ ] Initial release
- [ ] Explore: `useHibernatingEffect` hook (successfully prototyped)
Expand Down
104 changes: 104 additions & 0 deletions helpers/components/DemoContainer.tsx
@@ -0,0 +1,104 @@
import React, { ReactElement } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import Button from '@material-ui/core/Button';
import Grid from '@material-ui/core/Grid';
import TextField from '@material-ui/core/TextField';

import NestedState from './NestedState';

import { countAction, HelperState } from '../redux';

export interface DemoContainerProps {
title: string;
withRedux?: boolean;
}

const selectEntireState = (state: HelperState): HelperState => state;

let totalInstanceCount = 0;

const DemoContainer: React.FC<DemoContainerProps> = (props: DemoContainerProps): ReactElement => {
const { title, withRedux } = props;

// A simple per-Component instance counter
const myInstanceNumRef = React.useRef(0);
if (!myInstanceNumRef.current) {
totalInstanceCount++;
myInstanceNumRef.current = totalInstanceCount;
}
const myInstanceNum = myInstanceNumRef.current;

const titleWithMyInstanceNum = `${title} (#${myInstanceNum})`;

const mountTimeString = React.useRef(new Date().toUTCString()).current;
const renderCount = ++React.useRef(0).current;

React.useEffect((): (() => void) => {
console.log(`DemoContainer ${titleWithMyInstanceNum} mounted`);
return (): void => console.log(`DemoContainer ${titleWithMyInstanceNum} unmounted`);
}, []);

React.useEffect(() => {
console.log(`DemoContainer ${titleWithMyInstanceNum} rendered`);
});

// Our own local state
const [value1, setValue1] = React.useState('');
// Global state, if appropriate
let reduxContent;
if (withRedux) {
const state = useSelector(selectEntireState);
const dispatch = useDispatch();

reduxContent = (
<Grid item xs={4}>
<p>A redux-connected component</p>
<Button
variant="contained"
onClick={(): void => {
dispatch(countAction());
}}
>
Dispatch a counter update
</Button>
<pre>{JSON.stringify(state, null, 2)}</pre>
</Grid>
);
}

return (
<fieldset>
<legend>DemoContainer: {titleWithMyInstanceNum}</legend>
<p>
Mounted at {mountTimeString}, rendered {renderCount} times.
</p>
<Grid container>
<Grid item xs={4}>
<p>Controlled input: value is in DemoContainer&apos;s state</p>
<TextField
label="Component state"
variant="outlined"
value={value1}
onChange={(e): void => {
setValue1(e.target.value);
}}
/>

<p>Raw input: value is in dom only</p>
<TextField label="DOM state" variant="outlined" />
</Grid>
<Grid item xs={4}>
<p>Nested components with their own state</p>
<NestedState />
<NestedState />
</Grid>
{!!withRedux && reduxContent}
</Grid>
</fieldset>
);
};
DemoContainer.defaultProps = {
withRedux: false,
};

export default DemoContainer;
19 changes: 19 additions & 0 deletions helpers/components/NestedState.tsx
@@ -0,0 +1,19 @@
import React, { ReactElement } from 'react';
import Button from '@material-ui/core/Button';

const NestedState: React.FC = (): ReactElement => {
const [counterValue, setCounterValue] = React.useState(0);

return (
<Button
variant="contained"
onClick={(): void => {
setCounterValue((value) => value + 1);
}}
>
I&apos;ve been clicked {counterValue} {counterValue === 1 ? 'time' : 'times'}
</Button>
);
};

export default NestedState;
77 changes: 0 additions & 77 deletions helpers/components/SampleForm.tsx

This file was deleted.

6 changes: 4 additions & 2 deletions helpers/components/index.ts
@@ -1,2 +1,4 @@
export { default as SampleForm } from './SampleForm';
export * from './SampleForm';
export { default as DemoContainer } from './DemoContainer';
export * from './DemoContainer';
export { default as NestedState } from './NestedState';
export * from './NestedState';
4 changes: 2 additions & 2 deletions helpers/redux/store.ts
Expand Up @@ -4,11 +4,11 @@ import { composeWithDevTools } from 'redux-devtools-extension';
// We only need one action: this is all to demonstrate that updates can be frozen
const COUNT_ACTION = 'COUNT_ACTION';

type HelperState = {
export type HelperState = {
count: number;
lastTimestamp: number;
};
type HelperAction = {
export type HelperAction = {
type: typeof COUNT_ACTION;
};

Expand Down
2 changes: 2 additions & 0 deletions package.json
Expand Up @@ -62,6 +62,7 @@
},
"devDependencies": {
"@babel/core": "^7.8.4",
"@material-ui/core": "^4.9.4",
"@storybook/addon-knobs": "^5.3.14",
"@storybook/addons": "^5.3.14",
"@storybook/preset-typescript": "^1.2.0",
Expand Down Expand Up @@ -104,6 +105,7 @@
"ts-jest": "^25.2.1",
"ts-loader": "^6.2.1",
"tslib": "^1.10.0",
"typeface-roboto": "^0.0.75",
"typescript": "^3.7.5",
"yarn-or-npm": "^3.0.1"
},
Expand Down
2 changes: 1 addition & 1 deletion src/StaticContainers/index.ts
@@ -1,4 +1,4 @@
export { default as StaticComponentContainer } from './StaticComponentContainer';
export * from './StaticComponentContainer';
export { default as HibernatingRoute } from './StaticReduxContainer';
export { default as StaticReduxContainer } from './StaticReduxContainer';
export * from './StaticReduxContainer';
37 changes: 25 additions & 12 deletions stories/index.stories.tsx
Expand Up @@ -2,11 +2,14 @@ import * as React from 'react';
import { ReactElement, ReactNode } from 'react';
import { MemoryRouter, Redirect, Route, RouteProps } from 'react-router';
import { NavLink } from 'react-router-dom';
import Typography from '@material-ui/core/Typography';
import { withKnobs, number } from '@storybook/addon-knobs';

import 'typeface-roboto';

import { HibernatingRoute, HibernatingSwitch } from '../src';

import SampleForm from '../helpers/components/SampleForm';
import DemoContainer from '../helpers/components/DemoContainer';

export default {
title: 'Basic usage',
Expand All @@ -30,15 +33,19 @@ export const MaxCacheTimeOneMinute = (): ReactNode => {
{' | '}
<NavLink to="/route3/3">Route3 id=3</NavLink>

<Typography variant="subtitle1">
After leaving a screen, its state will be retained for one minute
</Typography>

<HibernatingSwitch maxCacheSize={maxCacheSize} maxCacheTime={maxCacheTime}>
<HibernatingRoute path="/route1">
<SampleForm title="Route 1" />
<DemoContainer title="Route 1" />
</HibernatingRoute>
<HibernatingRoute path="/route2">
<SampleForm title="Route 2" />
<DemoContainer title="Route 2" />
</HibernatingRoute>
<HibernatingRoute path="/route3/:id">
<SampleForm title="Route 3" />
<DemoContainer title="Route 3" />
</HibernatingRoute>
</HibernatingSwitch>
</MemoryRouter>
Expand All @@ -61,15 +68,17 @@ export const MaxCacheSizeOne = (): ReactNode => {
{' | '}
<NavLink to="/route3/3">Route3 id=3</NavLink>

<Typography variant="subtitle1">Only the last screen you visited will be retained</Typography>

<HibernatingSwitch maxCacheSize={maxCacheSize} maxCacheTime={maxCacheTime}>
<HibernatingRoute path="/route1">
<SampleForm title="Route 1" />
<DemoContainer title="Route 1" />
</HibernatingRoute>
<HibernatingRoute path="/route2">
<SampleForm title="Route 2" />
<DemoContainer title="Route 2" />
</HibernatingRoute>
<HibernatingRoute path="/route3/:id">
<SampleForm title="Route 3" />
<DemoContainer title="Route 3" />
</HibernatingRoute>
</HibernatingSwitch>
</MemoryRouter>
Expand All @@ -84,25 +93,29 @@ export const MixRoutesAndHibernatingRoutes = (): ReactNode => {

return (
<MemoryRouter initialEntries={['/not-matched']}>
<NavLink to="/route1">Default Route</NavLink>
<NavLink to="/route1">Non-hibernating Route 1</NavLink>
{' | '}
<NavLink to="/route2">Custom Route</NavLink>
<NavLink to="/route2">Non-hibernating Route 2</NavLink>
{' | '}
<NavLink to="/route3/1">Hibernating id=1</NavLink>
{' | '}
<NavLink to="/route3/2">Hibernating id=2</NavLink>
{' | '}
<NavLink to="/route3/3">Hibernating id=3</NavLink>

<Typography variant="subtitle1">
The first two screens are never retained, the last three are
</Typography>

<HibernatingSwitch maxCacheSize={maxCacheSize} maxCacheTime={maxCacheTime}>
<Route path="/route1">
<SampleForm title="Route 1" />
<DemoContainer title="Route 1" />
</Route>
<MyCustomRoute path="/route2">
<SampleForm title="Route 2" />
<DemoContainer title="Route 2" />
</MyCustomRoute>
<HibernatingRoute path="/route3/:id">
<SampleForm title="Route 3" />
<DemoContainer title="Route 3" />
</HibernatingRoute>
<Redirect to="/route1" />
</HibernatingSwitch>
Expand Down

0 comments on commit ac0d1b1

Please sign in to comment.