React custom hooks
by jonahe
HTML
<div id="app"></div>
CSS
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
.done {
color: rgba(0, 0, 0, 0.3);
text-decoration: line-through;
}
input {
margin-right: 5px;
}
React
const { useState, useCallback} = React;
function useSequenceStates({possibleStates = [], startStateIndex = 0, shouldLoop = false}) {
const [currentStateIndex, setCurrentStateIndex] = useState(startStateIndex);
const goToNextState = useCallback(() => {
const highestAllowedIndex = possibleStates.length - 1;
const nextIndex = currentStateIndex + 1;
if(nextIndex <= highestAllowedIndex) {
setCurrentStateIndex(nextIndex);
} else {
if(shouldLoop) {
setCurrentStateIndex(0);
} else {
console.warn("no next state");
}
}
}, [currentStateIndex, possibleStates, shouldLoop]);
const goToPreviousState = useCallback(() => {
const lowerstAllowedIndex = 0;
const previousIndex = currentStateIndex - 1;
if(previousIndex >= lowerstAllowedIndex) {
setCurrentStateIndex(previousIndex);
} else {
if(shouldLoop) {
setCurrentStateIndex(possibleStates.length - 1);
} else {
console.warn("no previous state");
}
}
}, [currentStateIndex, possibleStates, shouldLoop]);
const currentState = possibleStates[currentStateIndex];
return [currentState, { goToPreviousState, goToNextState}];
}
function Test() {
const [allowedStates, setAllowedStates ] = useState(["a", "b", "c", "d", "f"]);
const allowedStates2 = [1,2,3,4];
const [currentState, { goToPreviousState, goToNextState}] = useSequenceStates({possibleStates: allowedStates, shouldLoop: true });
const [currentState2, { goToPreviousState: goToPreviousState2 , goToNextState: goToNextState2 }] = useSequenceStates({possibleStates: allowedStates2, shouldLoop: true });
return (
<div>
<h2>space separated list of allowed states</h2>
<input type="text" value={ allowedStates.join(" ")} onChange={ evt => setAllowedStates(evt.target.value.split(" "))} />
<hr/>
<h2>1: {currentState}</h2>
<div>
<button onClick={goToPreviousState}>
previous state
...