React
by Abdul Ahmad
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
function App() {
const { valPromise } = useSomeHook();
const [state, setState] = React.useState();
React.useEffect(() => {
valPromise.then(r => {
setState(r);
});
}, []);
if (!state) return 'not resolved yet';
return 'resolved: ' + state;
}
function usePromiseValue() {
const resolveRef = React.useRef();
const promiseRef = React.useRef(createPromise({ resolve: res }));
const reset = React.useCallback(() => {
promise.current = createPromise({ resolve });
}, []);
const promise = promiseRef.current;
const resolve = resolveRef.current;
React.useEffect(() => {
}, [promise.current]);
return {
promise,
resolve,
reset,
};
}
function createPromise({ resolve } = {}) {
return new Promise(_resolve => {
// - useRef is actually called on every render, but the
// subsequent result is discarded
// - however, this can cause the `resolve.current` to be overwritten
// which will make the initial promise unresolvable
// - this condition takes care of ensuring we always resolve the
// first promise
if (!resolve.current) resolve.current = _resolve;
});
}
function useSomeHook() {
const [state, setState] = React.useState();
const { resolve, promise: valPromise, reset } = usePromiseValue({ dependencies: [state] });
React.useEffect(() => {
getValTimeout({ setState });
toggleValue({ setState });
}, []);
React.useEffect(() => {
if (!state) return;
console.log('*** state', state);
resolve(state);
reset();
}, [state]);
return { valPromise };
}
function getValTimeout({ setState }) {
setTimeout(() => {
setState('the val');
}, 1000);
}
let count = 0;
function toggleValue({ setState }) {
setInterval(() => {
count += 1;
setState(count);
}, 2000);
}
ReactDOM.render(<App />, document.querySelector("#app"))