So I had to change a lot. Usually I don't do this but it seemed quick to do. Here's a react counter with history;
import React, { useState, useCallback } from "react";
import Context from "./Context";
const ContextProvider = props => {
const [hist, setHist] = useState({
past: [],
present: 0,
future: []
});
const incr = useCallback(() => {
setHist(({ past, present }) => {
past = [...past, present];
return {
past,
present: present + 1
};
});
}, []);
const decr = useCallback(() => {
setHist(({ past, present }) => {
past = [...past, present];
return {
past,
present: present - 1
};
});
}, []);
const undo = useCallback(() => {
setHist(hist => {
let { past, present, future = [] } = hist;
past = [...past];
future = [...future, present];
present = past.pop();
console.log("undo:", past, present, future);
return {
past,
present,
future
};
});
}, []);
const redo = useCallback(() => {
setHist(hist => {
let { past, present, future } = hist;
if (future && future.length > 0) {
future = [...future];
past = [...past, present];
present = future.pop();
return {
past,
present,
future
};
}
return hist;
});
}, []);
return (
<Context.Provider
value={{
count: hist.present,
incr,
decr,
undo,
redo
}}
>
{props.children}
</Context.Provider>
);
};
export default ContextProvider;
With duplicate counter state
import React, { useState, useCallback } from "react";
import Context from "./Context";
const ContextProvider = props => {
const [count, setCount] = useState(0);
const [, setHist] = useState({
past: [],
present: 0,
future: []
});
const incr = useCallback(() => {
setHist(({ past, present }) => {
past = [...past, present];
let nC = count + 1;
setCount(nC);
return {
past,
present: nC
};
});
}, [count]);
const decr = useCallback(() => {
setHist(({ past, present }) => {
past = [...past, present];
let nC = count - 1;
setCount(nC);
return {
past,
present: nC
};
});
}, [count]);
const undo = useCallback(() => {
setHist(hist => {
let { past, present, future = [] } = hist;
past = [...past];
future = [...future, present];
present = past.pop();
setCount(present);
console.log("undo:", past, present, future);
return {
past,
present,
future
};
});
}, []);
const redo = useCallback(() => {
setHist(hist => {
let { past, present, future } = hist;
if (future && future.length > 0) {
future = [...future];
past = [...past, present];
present = future.pop();
setCount(present);
return {
past,
present,
future
};
}
return hist;
});
}, []);
return (
<Context.Provider
value={{
count,
incr,
decr,
undo,
redo
}}
>
{props.children}
</Context.Provider>
);
};
export default ContextProvider;
https://codesandbox.io/s/heuristic-cherry-oqted
historyarray and a pointercurrentIndexthat points to wherever the current historical value is (for normal operation, this would be the last element in the array). I'm not clear what gooduseEffectdoes here; seems like everything is synchronous.createContext?