stremio-web/src/common/useModelState.js
2020-02-03 18:06:54 +02:00

62 lines
2.1 KiB
JavaScript

const React = require('react');
const throttle = require('lodash.throttle');
const { useRouteFocused } = require('stremio-router');
const { useServices } = require('stremio/services');
const useDeepEqualState = require('stremio/common/useDeepEqualState');
const UNLOAD_ACTION = {
action: 'Unload',
};
const useModelState = ({ model, init, action, timeout, onNewState, map, mapWithCtx }) => {
const modelRef = React.useRef(model);
const mountedRef = React.useRef(false);
const { core } = useServices();
const routeFocused = useRouteFocused();
const [state, setState] = useDeepEqualState(init);
React.useLayoutEffect(() => {
core.dispatch(action, modelRef.current);
}, [action]);
React.useLayoutEffect(() => {
return () => {
core.dispatch(UNLOAD_ACTION, modelRef.current);
};
}, []);
React.useLayoutEffect(() => {
const onNewStateThrottled = throttle(() => {
const state = core.getState(modelRef.current);
if (typeof onNewState === 'function') {
const action = onNewState(state);
const handled = core.dispatch(action, modelRef.current);
if (handled) {
return;
}
}
if (typeof mapWithCtx === 'function') {
const ctx = core.getState('ctx');
setState(mapWithCtx(state, ctx));
} else if (typeof map === 'function') {
setState(map(state));
} else {
setState(state);
}
}, timeout);
if (routeFocused) {
core.on('NewState', onNewStateThrottled);
if (mountedRef.current) {
onNewStateThrottled.call();
}
}
return () => {
onNewStateThrottled.cancel();
core.off('NewState', onNewStateThrottled);
};
}, [routeFocused, timeout, onNewState, map, mapWithCtx]);
React.useLayoutEffect(() => {
mountedRef.current = true;
}, []);
return state;
};
module.exports = useModelState;