Last active
December 2, 2020 18:30
-
-
Save james2doyle/5d72bbc83edbe51f45c117a7e2738323 to your computer and use it in GitHub Desktop.
Use hyperactiv to recreate hooks with Javascript Proxy objects. Supports Redux devtool
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import setState from 'use-state.js'; | |
const [state, onStateUpdated] = useState('my-state', { count: 1 }); | |
console.log(state.count); // logs: "1" | |
// runs on init in order to compute dependencies | |
onStateUpdated((/* newState, originalState */) => { | |
console.log('stateUpdated', state.count); // logs: "stateUpdated 1" | |
}); | |
state.count = state.count + 1; // logs: "stateUpdated 2" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://github.com/elbywan/hyperactiv#description | |
import hyperactiv from 'hyperactiv'; | |
const { observe, computed } = hyperactiv; | |
const DEBUG = true; | |
const noop = () => ({}); | |
const fakeRedux = DEBUG ? { | |
// eslint-disable-next-line no-console | |
init: console.log.bind(console), | |
subscribe: noop, | |
// eslint-disable-next-line no-console | |
send: console.log.bind(console), | |
} : { | |
init: noop, | |
subscribe: noop, | |
send: noop, | |
}; | |
const extension = window.__REDUX_DEVTOOLS_EXTENSION__ || window.top.__REDUX_DEVTOOLS_EXTENSION__ || { connect: () => fakeRedux }; | |
const ReduxTool = extension.connect({ | |
trace: true, | |
}); | |
/** | |
* Create an observable object and listen to the state | |
* | |
* @param {string} name | |
* @param {object} state | |
* @param {object} options = {} | |
*/ | |
export default function useState(name, state, options = {}) { | |
const originalState = JSON.parse(JSON.stringify(state)); | |
let binding = noop; | |
const observeOptions = { | |
deep: true, | |
batch: true, // debounce calls | |
bubble: true, // bubble needs to be true if you want to call the __handler with nested objects | |
...options | |
}; | |
let observed = observe(state, observeOptions); | |
if (DEBUG) { | |
ReduxTool.subscribe(message => { | |
if (message.type === 'DISPATCH' && message.state) { | |
observed = observe(JSON.parse(message.state), observeOptions); | |
// call our original callback with the state being sent from the redux devtools | |
binding(observed, originalState); | |
} | |
}); | |
// first run of the computed function will push the new state and trigger but | |
// we want to skip that state change as the history will have a double state | |
let skipFirstComputed = true; | |
observed.__handler = (/* keys, value, oldValue, observedObject */) => { | |
const payload = JSON.parse(JSON.stringify(observed)); | |
if (!skipFirstComputed) { | |
ReduxTool.send({ type: `${name}-change`, payload }, observed); | |
} | |
skipFirstComputed = false; | |
}; | |
// start with an empty state | |
ReduxTool.init({}); | |
} | |
return [ | |
observed, | |
(fn) => { | |
binding = fn; | |
return computed(binding.bind(null, observed, originalState)); | |
} | |
]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment