Skip to content

Commit

Permalink
feat: add useHistory
Browse files Browse the repository at this point in the history
  • Loading branch information
PerkinJ committed Mar 7, 2020
1 parent f5dcf7a commit ee2b8a2
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 4 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"react": "^16.13.0",
"react-dom": "^16.13.0",
"react-scripts": "3.4.0",
"regraph-next": "^0.0.1-beat4",
"regraph-next": "^0.0.1-beta1",
"typescript": "^3.7.5",
"uuid": "^3.3.2"
},
Expand Down
2 changes: 1 addition & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
<title>ReGraph Demo</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
Expand Down
4 changes: 2 additions & 2 deletions public/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"short_name": "ReGraph Demo",
"name": "Demo Based ReGraph",
"icons": [
{
"src": "favicon.ico",
Expand Down
98 changes: 98 additions & 0 deletions src/editor/hooks/useHistory.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { useReducer, useCallback } from 'react';

// Initial state that we pass into useReducer
const initialState = {
// Array of previous state values updated each time we push a new state
past: [],
// Current state value
present: null,
// Will contain "future" state values if we undo (so we can redo)
future: []
};

// Our reducer function to handle state changes based on action
const reducer = (state, action) => {
const { past, present, future } = state;
switch (action.type) {
case 'UNDO':
const previous = past[past.length - 1];
const newPast = past.slice(0, past.length - 1);

return {
past: newPast,
present: previous,
future: [present, ...future]
};
case 'REDO':
const next = future[0];
const newFuture = future.slice(1);

return {
past: [...past, present],
present: next,
future: newFuture
};
case 'SET':
const { newPresent } = action;

if (newPresent === present) {
return state;
}
return {
past: [...past, present],
present: newPresent,
future: []
};
case 'CLEAR':
const { initialPresent } = action;

return {
...initialState,
present: initialPresent
};
}
};

const useHistory = initialPresent => {
const [state, dispatch] = useReducer(reducer, {
...initialState,
present: initialPresent
});

const canUndo = state.past.length !== 0;
const canRedo = state.future.length !== 0;

// Setup our callback functions
// We memoize with useCallback to prevent unecessary re-renders

const undo = useCallback(
() => {
if (canUndo) {
dispatch({ type: 'UNDO' });
}
},
[canUndo, dispatch]
);

const redo = useCallback(
() => {
if (canRedo) {
dispatch({ type: 'REDO' });
}
},
[canRedo, dispatch]
);

const set = useCallback(newPresent => dispatch({ type: 'SET', newPresent }), [
dispatch
]);

const clear = useCallback(() => dispatch({ type: 'CLEAR', initialPresent }), [
dispatch
]);

// If needed we could also return past and future state
return { state: state.present, set, undo, redo, clear, canUndo, canRedo };
};

export default useHistory;

0 comments on commit ee2b8a2

Please sign in to comment.